diff --git a/applications/solvers/discreteMethods/dsmc/dsmcFoam/dsmcFoam.C b/applications/solvers/discreteMethods/dsmc/dsmcFoam/dsmcFoam.C index 1ea52cc6aa..cb068960e8 100644 --- a/applications/solvers/discreteMethods/dsmc/dsmcFoam/dsmcFoam.C +++ b/applications/solvers/discreteMethods/dsmc/dsmcFoam/dsmcFoam.C @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) runTime.write(); - Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s" + Info<< nl << "ExecutionTime = " << runTime.elapsedCpuTime() << " s" << " ClockTime = " << runTime.elapsedClockTime() << " s" << nl << endl; } diff --git a/src/lagrangian/basic/Particle/Particle.C b/src/lagrangian/basic/Particle/Particle.C index ec1d09a00f..6c8cbe4aa1 100644 --- a/src/lagrangian/basic/Particle/Particle.C +++ b/src/lagrangian/basic/Particle/Particle.C @@ -390,7 +390,7 @@ Foam::scalar Foam::Particle::trackToFace // slightly towards the cell-centre. if (trackFraction < SMALL) { - position_ += 1.0e-6*(mesh.cellCentres()[celli_] - position_); + position_ += 1.0e-3*(mesh.cellCentres()[celli_] - position_); } return trackFraction; diff --git a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.C b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.C index 4c4bcd0a43..53177e9afe 100644 --- a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.C +++ b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.C @@ -37,6 +37,7 @@ Foam::scalar Foam::DsmcCloud::kb = 1.380650277e-23; template Foam::scalar Foam::DsmcCloud::Tref = 273; + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template @@ -113,87 +114,161 @@ void Foam::DsmcCloud::initialise numberDensities /= nParticle_; - scalar x0 = mesh_.bounds().min().x(); - scalar xR = mesh_.bounds().max().x() - x0; - - scalar y0 = mesh_.bounds().min().y(); - scalar yR = mesh_.bounds().max().y() - y0; - - scalar z0 = mesh_.bounds().min().z(); - scalar zR = mesh_.bounds().max().z() - z0; - - forAll(molecules, i) + forAll(mesh_.cells(), cell) { - const word& moleculeName(molecules[i]); + const vector& cC = mesh_.cellCentres()[cell]; + const labelList& cellFaces = mesh_.cells()[cell]; + const scalar cV = mesh_.cellVolumes()[cell]; - label typeId(findIndex(typeIdList_, moleculeName)); + label nTets = 0; - if (typeId == -1) + // Each face is split into nEdges (or nVertices) - 2 tets. + forAll(cellFaces, face) { - FatalErrorIn("Foam::DsmcCloud::initialise") - << "typeId " << moleculeName << "not defined." << nl - << abort(FatalError); + nTets += mesh_.faces()[cellFaces[face]].size() - 2; } - const typename ParcelType::constantProperties& cP = constProps(typeId); + // Calculate the cumulative tet volumes circulating around the cell and + // record the vertex labels of each. + scalarList cTetVFracs(nTets, 0.0); - scalar numberDensity = numberDensities[i]; + List tetPtIs(nTets, labelList(3,-1)); - scalar spacing = pow(numberDensity,-(1.0/3.0)); + // Keep track of which tet this is. + label tet = 0; - int ni = label(xR/spacing) + 1; - int nj = label(yR/spacing) + 1; - int nk = label(zR/spacing) + 1; - - vector delta(xR/ni, yR/nj, zR/nk); - - scalar pert = spacing; - - for (int i = 0; i < ni; i++) + forAll(cellFaces, face) { - for (int j = 0; j < nj; j++) + const labelList& facePoints = mesh_.faces()[cellFaces[face]]; + + label pointI = 1; + while ((pointI + 1) < facePoints.size()) { - for (int k = 0; k < nk; k++) + + const vector& pA = mesh_.points()[facePoints[0]]; + const vector& pB = mesh_.points()[facePoints[pointI]]; + const vector& pC = mesh_.points()[facePoints[pointI + 1]]; + + cTetVFracs[tet] = + mag(((pA - cC) ^ (pB - cC)) & (pC - cC))/(cV*6.0) + + cTetVFracs[max((tet - 1),0)]; + + tetPtIs[tet][0] = facePoints[0]; + tetPtIs[tet][1] = facePoints[pointI]; + tetPtIs[tet][2] = facePoints[pointI + 1]; + + pointI++; + tet++; + } + } + + // Force the last volume fraction value to 1.0 to avoid any + // rounding/non-flat face errors giving a value < 1.0 + cTetVFracs[nTets - 1] = 1.0; + + forAll(molecules, i) + { + const word& moleculeName(molecules[i]); + + label typeId(findIndex(typeIdList_, moleculeName)); + + if (typeId == -1) + { + FatalErrorIn("Foam::DsmcCloud::initialise") + << "typeId " << moleculeName << "not defined." << nl + << abort(FatalError); + } + + const typename ParcelType::constantProperties& cP = + constProps(typeId); + + scalar numberDensity = numberDensities[i]; + + // Calculate the number of particles required + scalar particlesRequired = numberDensity*mesh_.cellVolumes()[cell]; + + // Only integer numbers of particles can be inserted + label nParticlesToInsert = label(particlesRequired); + + // Add another particle with a probability proportional to the + // remainder of taking the integer part of particlesRequired + if ((particlesRequired - nParticlesToInsert) > rndGen_.scalar01()) + { + nParticlesToInsert++; + } + + for (label pI = 0; pI < nParticlesToInsert; pI++) + { + // Choose a random point in a generic tetrahedron + + scalar s = rndGen_.scalar01(); + scalar t = rndGen_.scalar01(); + scalar u = rndGen_.scalar01(); + + if (s + t > 1.0) { - point p - ( - x0 + (i + 0.5)*delta.x(), - y0 + (j + 0.5)*delta.y(), - z0 + (k + 0.5)*delta.z() - ); + s = 1.0 - s; + t = 1.0 - t; + } - p.x() += pert*(rndGen_.scalar01() - 0.5); - p.y() += pert*(rndGen_.scalar01() - 0.5); - p.z() += pert*(rndGen_.scalar01() - 0.5); + if (t + u > 1.0) + { + scalar tmp = u; + u = 1.0 - s - t; + t = 1.0 - tmp; + } + else if (s + t + u > 1.0) + { + scalar tmp = u; + u = s + t + u - 1.0; + s = 1.0 - t - tmp; + } - label cell = mesh_.findCell(p); + // Choose a tetrahedron to insert in, based on their relative + // volumes + scalar tetSelection = rndGen_.scalar01(); - vector U = equipartitionLinearVelocity - ( - temperature, - cP.mass() - ); + // Selected tetrahedron + label sTet = -1; - scalar Ei = equipartitionInternalEnergy - ( - temperature, - cP.internalDegreesOfFreedom() - ); + forAll(cTetVFracs, tet) + { + sTet = tet; - U += velocity; - - if (cell >= 0) + if (cTetVFracs[tet] >= tetSelection) { - addNewParcel - ( - p, - U, - Ei, - cell, - typeId - ); + break; } } + + vector p = + (1 - s - t - u)*cC + + s*mesh_.points()[tetPtIs[sTet][0]] + + t*mesh_.points()[tetPtIs[sTet][1]] + + u*mesh_.points()[tetPtIs[sTet][2]]; + + vector U = equipartitionLinearVelocity + ( + temperature, + cP.mass() + ); + + scalar Ei = equipartitionInternalEnergy + ( + temperature, + cP.internalDegreesOfFreedom() + ); + + U += velocity; + + addNewParcel + ( + p, + U, + Ei, + cell, + typeId + ); } } } @@ -276,7 +351,7 @@ void Foam::DsmcCloud::collisions() scalar selectedPairs = collisionSelectionRemainder_[celli] - + 0.5*nC*(nC-1)*nParticle_*sigmaTcRMax*deltaT + + 0.5*nC*(nC - 1)*nParticle_*sigmaTcRMax*deltaT /mesh_.cellVolumes()[celli]; label nCandidates(selectedPairs); @@ -551,6 +626,13 @@ Foam::DsmcCloud::DsmcCloud buildConstProps(); buildCellOccupancy(); + + // Initialise the collision selection remainder to a random value between 0 + // and 1. + forAll(collisionSelectionRemainder_, i) + { + collisionSelectionRemainder_[i] = rndGen_.scalar01(); + } } @@ -739,22 +821,27 @@ void Foam::DsmcCloud::info() const Info<< "Cloud name: " << this->name() << nl << " Number of dsmc particles = " - << nDsmcParticles << nl - << " Number of molecules = " - << nMol << nl - << " Mass in system = " - << returnReduce(massInSystem(), sumOp()) << nl - << " Average linear momentum = " - << linearMomentum/nMol << nl - << " |Average linear momentum| = " - << mag(linearMomentum)/nMol << nl - << " Average linear kinetic energy = " - << linearKineticEnergy/nMol << nl - << " Average internal energy = " - << internalEnergy/nMol << nl - << " Average total energy = " - << (internalEnergy + linearKineticEnergy)/nMol << nl + << nDsmcParticles << endl; + + if (nDsmcParticles) + { + Info<< " Number of molecules = " + << nMol << nl + << " Mass in system = " + << returnReduce(massInSystem(), sumOp()) << nl + << " Average linear momentum = " + << linearMomentum/nMol << nl + << " |Average linear momentum| = " + << mag(linearMomentum)/nMol << nl + << " Average linear kinetic energy = " + << linearKineticEnergy/nMol << nl + << " Average internal energy = " + << internalEnergy/nMol << nl + << " Average total energy = " + << (internalEnergy + linearKineticEnergy)/nMol + << endl; + } } @@ -785,7 +872,11 @@ Foam::scalar Foam::DsmcCloud::equipartitionInternalEnergy { scalar Ei = 0.0; - if (iDof < 2.0 + SMALL && iDof > 2.0 - SMALL) + if (iDof < SMALL) + { + return Ei; + } + else if (iDof < 2.0 + SMALL && iDof > 2.0 - SMALL) { // Special case for iDof = 2, i.e. diatomics; Ei = -log(rndGen_.scalar01())*kb*temperature; @@ -796,7 +887,7 @@ Foam::scalar Foam::DsmcCloud::equipartitionInternalEnergy scalar energyRatio; - scalar P; + scalar P = -1; do { diff --git a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.H b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.H index b246b04990..20bed1ee7b 100644 --- a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.H +++ b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloud.H @@ -299,6 +299,12 @@ public: scalar mass ) const; + inline scalarField maxwellianAverageSpeed + ( + scalarField temperature, + scalar mass + ) const; + //- RMS particle speed inline scalar maxwellianRMSSpeed ( @@ -306,6 +312,12 @@ public: scalar mass ) const; + inline scalarField maxwellianRMSSpeed + ( + scalarField temperature, + scalar mass + ) const; + //- Most probable speed inline scalar maxwellianMostProbableSpeed ( @@ -313,6 +325,11 @@ public: scalar mass ) const; + inline scalarField maxwellianMostProbableSpeed + ( + scalarField temperature, + scalar mass + ) const; // Sub-models diff --git a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloudI.H b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloudI.H index 73899636e8..d39de4954f 100644 --- a/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloudI.H +++ b/src/lagrangian/dsmc/clouds/Templates/DsmcCloud/DsmcCloudI.H @@ -302,6 +302,17 @@ inline Foam::scalar Foam::DsmcCloud::maxwellianAverageSpeed } +template +inline Foam::scalarField Foam::DsmcCloud::maxwellianAverageSpeed +( + scalarField temperature, + scalar mass +) const +{ + return 2.0*sqrt(2.0*kb*temperature/(mathematicalConstant::pi*mass)); +} + + template inline Foam::scalar Foam::DsmcCloud::maxwellianRMSSpeed ( @@ -313,6 +324,17 @@ inline Foam::scalar Foam::DsmcCloud::maxwellianRMSSpeed } +template +inline Foam::scalarField Foam::DsmcCloud::maxwellianRMSSpeed +( + scalarField temperature, + scalar mass +) const +{ + return sqrt(3.0*kb*temperature/mass); +} + + template inline Foam::scalar Foam::DsmcCloud::maxwellianMostProbableSpeed @@ -325,6 +347,18 @@ Foam::DsmcCloud::maxwellianMostProbableSpeed } +template +inline Foam::scalarField +Foam::DsmcCloud::maxwellianMostProbableSpeed +( + scalarField temperature, + scalar mass +) const +{ + return sqrt(2.0*kb*temperature/mass); +} + + template inline const Foam::tmp Foam::DsmcCloud::rhoN() const @@ -343,7 +377,7 @@ Foam::DsmcCloud::rhoN() const false ), mesh_, - dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0) + dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL) ) ); @@ -380,7 +414,7 @@ Foam::DsmcCloud::rhoM() const false ), mesh_, - dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), 0.0) + dimensionedScalar("zero", dimensionSet(1, -3, 0, 0, 0), VSMALL) ) ); @@ -568,7 +602,7 @@ Foam::DsmcCloud::iDof() const false ), mesh_, - dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), 0.0) + dimensionedScalar("zero", dimensionSet(0, -3, 0, 0, 0), VSMALL) ) ); diff --git a/src/lagrangian/dsmc/submodels/InflowBoundaryModel/FreeStream/FreeStream.C b/src/lagrangian/dsmc/submodels/InflowBoundaryModel/FreeStream/FreeStream.C index f4203f4d66..cd18d9064d 100644 --- a/src/lagrangian/dsmc/submodels/InflowBoundaryModel/FreeStream/FreeStream.C +++ b/src/lagrangian/dsmc/submodels/InflowBoundaryModel/FreeStream/FreeStream.C @@ -36,32 +36,27 @@ Foam::FreeStream::FreeStream ) : InflowBoundaryModel(dict, cloud, typeName), - patchIndex_(), - temperature_(readScalar(this->coeffDict().lookup("temperature"))), - velocity_(this->coeffDict().lookup("velocity")), + patches_(), moleculeTypeIds_(), numberDensities_(), particleFluxAccumulators_() { - word patchName = this->coeffDict().lookup("patch"); + // Identify which patches to use - patchIndex_ = cloud.mesh().boundaryMesh().findPatchID(patchName); + DynamicList