38 template<
class ParcelType>
41 Info<<
nl <<
"Constructing constant properties for" <<
endl;
42 constProps_.setSize(typeIdList_.size());
44 dictionary moleculeProperties
46 particleProperties_.subDict(
"moleculeProperties")
51 const word& id(typeIdList_[i]);
55 const dictionary& molDict(moleculeProperties.subDict(
id));
58 typename ParcelType::constantProperties(molDict);
63 template<
class ParcelType>
68 cellOccupancy_[cO].clear();
71 forAllIter(
typename DSMCCloud<ParcelType>, *
this, iter)
73 cellOccupancy_[iter().cell()].append(&iter());
78 template<
class ParcelType>
81 const IOdictionary& dsmcInitialiseDict
86 const scalar temperature
88 dsmcInitialiseDict.template lookup<scalar>(
"temperature")
91 const vector velocity(dsmcInitialiseDict.lookup(
"velocity"));
93 const dictionary& numberDensitiesDict
95 dsmcInitialiseDict.subDict(
"numberDensities")
98 List<word> molecules(numberDensitiesDict.toc());
100 Field<scalar> numberDensities(molecules.size());
105 numberDensitiesDict.lookup<scalar>(molecules[i]);
108 numberDensities /= nParticle_;
110 label nLocateBoundaryHits = 0;
112 forAll(mesh_.cells(), celli)
122 const tetIndices& cellTetIs = cellTets[tetI];
124 scalar tetVolume = tet.mag();
128 const word& moleculeName(molecules[i]);
135 <<
"typeId " << moleculeName <<
"not defined." <<
nl
139 const typename ParcelType::constantProperties& cP =
142 scalar numberDensity = numberDensities[i];
145 scalar particlesRequired = numberDensity*tetVolume;
148 label nParticlesToInsert =
label(particlesRequired);
154 (particlesRequired - nParticlesToInsert)
158 nParticlesToInsert++;
161 for (
label pI = 0; pI < nParticlesToInsert; pI++)
163 point p = tet.randomPoint(rndGen_);
165 vector U = equipartitionLinearVelocity
171 scalar Ei = equipartitionInternalEnergy
174 cP.internalDegreesOfFreedom()
179 addNewParcel(
p, celli, nLocateBoundaryHits,
U, Ei, typeId);
185 reduce(nLocateBoundaryHits, sumOp<label>());
186 if (nLocateBoundaryHits != 0)
189 <<
"Initialisation of cloud " << this->
name()
190 <<
" did not accurately locate " << nLocateBoundaryHits
191 <<
" particles" <<
endl;
200 const typename ParcelType::constantProperties& cP = constProps
205 sigmaTcRMax_.primitiveFieldRef() = cP.sigmaT()*maxwellianMostProbableSpeed
211 sigmaTcRMax_.correctBoundaryConditions();
215 template<
class ParcelType>
218 if (
isType<NoBinaryCollision<DSMCCloud<ParcelType>>>(binaryCollision()))
224 List<DynamicList<label>> subCells(8);
226 scalar deltaT = mesh().time().deltaTValue();
228 label collisionCandidates = 0;
230 label collisions = 0;
232 forAll(cellOccupancy_, celli)
234 const DynamicList<ParcelType*>& cellParcels(cellOccupancy_[celli]);
236 label nC(cellParcels.size());
250 List<label> whichSubCell(cellParcels.size());
252 const point& cC = mesh_.cellCentres()[celli];
256 const ParcelType&
p = *cellParcels[i];
257 vector relPos =
p.position(mesh()) - cC;
260 pos0(relPos.x()) + 2*
pos0(relPos.y()) + 4*
pos0(relPos.z());
262 subCells[subCell].append(i);
263 whichSubCell[i] = subCell;
268 scalar sigmaTcRMax = sigmaTcRMax_[celli];
270 scalar selectedPairs =
271 collisionSelectionRemainder_[celli]
272 + 0.5*nC*(nC - 1)*nParticle_*sigmaTcRMax*deltaT
273 /mesh_.cellVolumes()[celli];
275 label nCandidates(selectedPairs);
276 collisionSelectionRemainder_[celli] = selectedPairs - nCandidates;
277 collisionCandidates += nCandidates;
279 for (
label c = 0;
c < nCandidates;
c++)
285 label candidateP = rndGen_.sampleAB<
label>(0, nC);
288 label candidateQ = -1;
290 List<label> subCellPs = subCells[whichSubCell[candidateP]];
291 label nSC = subCellPs.size();
301 candidateQ = subCellPs[rndGen_.sampleAB<
label>(0, nSC)];
302 }
while (candidateP == candidateQ);
312 candidateQ = rndGen_.sampleAB<
label>(0, nC);
313 }
while (candidateP == candidateQ);
333 ParcelType& parcelP = *cellParcels[candidateP];
334 ParcelType& parcelQ = *cellParcels[candidateQ];
336 scalar sigmaTcR = binaryCollision().sigmaTcR
346 if (sigmaTcR > sigmaTcRMax_[celli])
348 sigmaTcRMax_[celli] = sigmaTcR;
351 if ((sigmaTcR/sigmaTcRMax) > rndGen_.scalar01())
353 binaryCollision().collide
365 reduce(collisions, sumOp<label>());
367 reduce(collisionCandidates, sumOp<label>());
369 sigmaTcRMax_.correctBoundaryConditions();
371 if (collisionCandidates)
373 Info<<
" Collisions = "
375 <<
" Acceptance rate = "
376 << scalar(collisions)/scalar(collisionCandidates) <<
nl
386 template<
class ParcelType>
394 dimensionSet(1, -1, -2, 0, 0),
408 dimensionSet(1, -2, -1, 0, 0),
414 template<
class ParcelType>
419 scalarField& dsmcRhoN = dsmcRhoN_.primitiveFieldRef();
420 scalarField& linearKE = linearKE_.primitiveFieldRef();
421 scalarField& internalE = internalE_.primitiveFieldRef();
423 vectorField& momentum = momentum_.primitiveFieldRef();
427 const ParcelType&
p = iter();
428 const label celli =
p.cell();
431 rhoM[celli] += constProps(
p.typeId()).mass();
433 linearKE[celli] += 0.5*constProps(
p.typeId()).mass()*(
p.U() &
p.U());
434 internalE[celli] +=
p.Ei();
435 iDof[celli] += constProps(
p.typeId()).internalDegreesOfFreedom();
436 momentum[celli] += constProps(
p.typeId()).mass()*
p.U();
439 rhoN *= nParticle_/mesh().cellVolumes();
440 rhoN_.correctBoundaryConditions();
442 rhoM *= nParticle_/mesh().cellVolumes();
443 rhoM_.correctBoundaryConditions();
445 dsmcRhoN_.correctBoundaryConditions();
447 linearKE *= nParticle_/mesh().cellVolumes();
448 linearKE_.correctBoundaryConditions();
450 internalE *= nParticle_/mesh().cellVolumes();
451 internalE_.correctBoundaryConditions();
453 iDof *= nParticle_/mesh().cellVolumes();
454 iDof_.correctBoundaryConditions();
456 momentum *= nParticle_/mesh().cellVolumes();
457 momentum_.correctBoundaryConditions();
463 template<
class ParcelType>
468 label& nLocateBoundaryHits,
492 template<
class ParcelType>
508 mesh_.time().constant(),
514 typeIdList_(particleProperties_.lookup(
"typeIdList")),
517 particleProperties_.template lookup<scalar>(
"nEquivalentParticles")
519 cellOccupancy_(mesh_.nCells()),
524 this->
name() +
"SigmaTcRMax",
532 collisionSelectionRemainder_
536 this->
name() +
":collisionSelectionRemainder",
652 rndGen_(
label(149382906)),
653 stdNormal_(rndGen_.generator()),
684 binaryCollisionModel_
692 wallInteractionModel_
710 buildCellOccupancy();
714 forAll(collisionSelectionRemainder_, i)
716 collisionSelectionRemainder_[i] = rndGen_.
scalar01();
726 template<
class ParcelType>
742 mesh_.time().constant(),
748 typeIdList_(particleProperties_.lookup(
"typeIdList")),
751 particleProperties_.template lookup<scalar>(
"nEquivalentParticles")
758 this->
name() +
"SigmaTcRMax",
766 zeroGradientFvPatchScalarField::typeName
768 collisionSelectionRemainder_
772 this->
name() +
":collisionSelectionRemainder",
796 this->
name() +
"fD_",
814 this->
name() +
"rhoN_",
827 this->
name() +
"rhoM_",
840 this->
name() +
"dsmcRhoN_",
853 this->
name() +
"linearKE_",
866 this->
name() +
"internalE_",
879 this->
name() +
"iDof_",
892 this->
name() +
"momentum_",
907 rndGen_(
label(971501)),
908 stdNormal_(rndGen_.generator()),
946 binaryCollisionModel_(),
947 wallInteractionModel_(),
948 inflowBoundaryModel_()
952 initialise(dsmcInitialiseDict);
958 template<
class ParcelType>
965 template<
class ParcelType>
968 typename ParcelType::trackingData td(*
this);
975 this->dumpParticlePositions();
979 this->inflowBoundary().inflow();
985 buildCellOccupancy();
995 template<
class ParcelType>
998 label nDSMCParticles = this->size();
1001 scalar nMol = nDSMCParticles*nParticle_;
1003 vector linearMomentum = linearMomentumOfSystem();
1006 scalar linearKineticEnergy = linearKineticEnergyOfSystem();
1009 scalar internalEnergy = internalEnergyOfSystem();
1013 <<
" Number of dsmc particles = "
1019 Info<<
" Number of molecules = "
1021 <<
" Mass in system = "
1023 <<
" Average linear momentum = "
1024 << linearMomentum/nMol <<
nl
1025 <<
" |Average linear momentum| = "
1026 <<
mag(linearMomentum)/nMol <<
nl
1027 <<
" Average linear kinetic energy = "
1028 << linearKineticEnergy/nMol <<
nl
1029 <<
" Average internal energy = "
1030 << internalEnergy/nMol <<
nl
1031 <<
" Average total energy = "
1032 << (internalEnergy + linearKineticEnergy)/nMol
1038 template<
class ParcelType>
1047 *stdNormal_.sample<
vector>();
1051 template<
class ParcelType>
1071 scalar a = 0.5*iDof - 1;
1077 energyRatio = 10*rndGen_.scalar01();
1078 P =
pow((energyRatio/a), a)*
exp(a - energyRatio);
1079 }
while (P < rndGen_.scalar01());
1088 template<
class ParcelType>
1093 this->db().time().path()/
"parcelPositions_"
1094 + this->
name() +
"_"
1095 + this->db().time().
name() +
".obj"
1100 const point pos = iter().position(mesh());
1102 pObj<<
"v " <<
pos.x() <<
" " <<
pos.y() <<
" " <<
pos.z() <<
nl;
1109 template<
class ParcelType>
1115 cellOccupancy_.setSize(mesh_.nCells());
1116 buildCellOccupancy();
1119 this->inflowBoundary().topoChange();
1123 template<
class ParcelType>
1129 cellOccupancy_.setSize(mesh_.nCells());
1130 buildCellOccupancy();
1133 this->inflowBoundary().topoChange();
1137 template<
class ParcelType>
1143 cellOccupancy_.setSize(mesh_.nCells());
1144 buildCellOccupancy();
1147 this->inflowBoundary().topoChange();
#define forAll(list, i)
Loop across all elements in list.
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Templated DSMC particle collision class.
Base cloud calls templated on particle type.
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
virtual void distribute(const polyDistributionMap &)
Redistribute or update using the given distribution map.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
void move(TrackCloudType &cloud, typename ParticleType::trackingData &td)
Move the particles.
Templated base class for dsmc cloud.
void addNewParcel(const vector &position, const label celli, label &nLocateBoundaryHits, const vector &U, const scalar Ei, const label typeId)
Add new parcel.
DSMCCloud(const word &cloudName, const fvMesh &mesh, bool readFields=true)
Construct given name and mesh, will read Parcels and fields from.
virtual ~DSMCCloud()
Destructor.
vector equipartitionLinearVelocity(scalar temperature, scalar mass)
Generate a random velocity sampled from the Maxwellian speed.
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
virtual void distribute(const polyDistributionMap &)
Redistribute or update using the given distribution map.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
void evolve()
Evolve the cloud (move, collide)
scalar equipartitionInternalEnergy(scalar temperature, direction internalDegreesOfFreedom)
Generate a random internal energy, sampled from the.
void clear()
Clear the Cloud.
void dumpParticlePositions() const
Dump particle positions to .obj file.
void info() const
Print cloud information.
Generic GeometricField class.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Templated inflow boundary model class.
virtual void flush()
Flush stream.
Templated wall interaction model class.
Dimension set for the base types.
Mesh data needed to do the Finite Volume discretisation.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
Class containing mesh-to-mesh mapping information.
static List< tetIndices > cellTetIndices(const polyMesh &mesh, label cI)
Return the tet decomposition of the given cell, see.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
scalar scalar01()
Return a scalar uniformly distributed between zero and one.
A class for handling words, derived from string.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
dimensionedScalar pos(const dimensionedScalar &ds)
dimensionedScalar exp(const dimensionedScalar &ds)
dimensionedScalar pos0(const dimensionedScalar &ds)
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
label findMax(const ListType &, const label start=0)
Find index of max element (and larger than given element).
Ostream & endl(Ostream &os)
Add newline and flush stream.
word name(const bool)
Return a word representation of a bool.
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const HashSet< word > &selectedFields, LIFOStack< regIOobject * > &storedObjects)
Read the selected GeometricFields of the specified type.
errorManip< error > abort(error &err)
const dimensionSet dimless
bool isType(const Type &t)
Check the typeid.
vector point
Point is a vector.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensionedScalar log(const dimensionedScalar &ds)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Vector< scalar > vector
A scalar version of the templated Vector.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
dimensionedScalar sqrt(const dimensionedScalar &ds)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< scalar > mag(const dimensioned< Type > &)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Field< vector > vectorField
Specialisation of Field<T> for vector.
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tetrahedron< point, const point & > tetPointRef
const word cloudName(propsDict.lookup("cloudName"))