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
88 dsmcInitialiseDict.template lookup<scalar>(
"temperature")
93 const dictionary& numberDensitiesDict
95 dsmcInitialiseDict.subDict(
"numberDensities")
100 List<word> molecules(numberDensitiesDict.toc());
102 Field<scalar> numberDensities(molecules.size());
107 numberDensitiesDict.lookup<scalar>(molecules[i]);
110 numberDensities /= nParticle_;
112 label nLocateBoundaryHits = 0;
114 forAll(mesh_.cells(), celli)
124 const tetIndices& cellTetIs = cellTets[tetI];
126 scalar tetVolume = tet.mag();
130 const word& moleculeName(molecules[i]);
137 <<
"typeId " << moleculeName <<
"not defined." <<
nl
141 const typename ParcelType::constantProperties& cP =
144 scalar numberDensity = numberDensities[i];
147 scalar particlesRequired = numberDensity*tetVolume;
150 label nParticlesToInsert =
label(particlesRequired);
156 (particlesRequired - nParticlesToInsert)
160 nParticlesToInsert++;
163 for (
label pI = 0; pI < nParticlesToInsert; pI++)
165 point p = tet.randomPoint(rndGen_);
167 vector U = equipartitionLinearVelocity
173 scalar Ei = equipartitionInternalEnergy
176 cP.internalDegreesOfFreedom()
196 reduce(nLocateBoundaryHits, sumOp<label>());
197 if (nLocateBoundaryHits != 0)
200 <<
"Initialisation of cloud " << this->
name()
201 <<
" did not accurately locate " << nLocateBoundaryHits
202 <<
" particles" <<
endl;
211 const typename ParcelType::constantProperties& cP = constProps
216 sigmaTcRMax_.primitiveFieldRef() = cP.sigmaT()*maxwellianMostProbableSpeed
222 sigmaTcRMax_.correctBoundaryConditions();
226 template<
class ParcelType>
229 if (
isType<NoBinaryCollision<DSMCCloud<ParcelType>>>(binaryCollision()))
239 label collisionCandidates = 0;
241 label collisions = 0;
243 forAll(cellOccupancy_, celli)
245 const DynamicList<ParcelType*>& cellParcels(cellOccupancy_[celli]);
247 label nC(cellParcels.size());
263 const point& cC = mesh_.cellCentres()[celli];
267 const ParcelType&
p = *cellParcels[i];
271 pos0(relPos.x()) + 2*
pos0(relPos.y()) + 4*
pos0(relPos.z());
273 subCells[subCell].append(i);
274 whichSubCell[i] = subCell;
279 scalar sigmaTcRMax = sigmaTcRMax_[celli];
281 scalar selectedPairs =
282 collisionSelectionRemainder_[celli]
283 + 0.5*nC*(nC - 1)*nParticle_*sigmaTcRMax*deltaT
284 /mesh_.cellVolumes()[celli];
286 label nCandidates(selectedPairs);
287 collisionSelectionRemainder_[celli] = selectedPairs - nCandidates;
288 collisionCandidates += nCandidates;
290 for (
label c = 0;
c < nCandidates;
c++)
296 label candidateP = rndGen_.sampleAB<
label>(0, nC);
299 label candidateQ = -1;
301 List<label> subCellPs = subCells[whichSubCell[candidateP]];
302 label nSC = subCellPs.size();
312 candidateQ = subCellPs[rndGen_.sampleAB<
label>(0, nSC)];
313 }
while (candidateP == candidateQ);
323 candidateQ = rndGen_.sampleAB<
label>(0, nC);
324 }
while (candidateP == candidateQ);
344 ParcelType& parcelP = *cellParcels[candidateP];
345 ParcelType& parcelQ = *cellParcels[candidateQ];
347 scalar sigmaTcR = binaryCollision().sigmaTcR
357 if (sigmaTcR > sigmaTcRMax_[celli])
359 sigmaTcRMax_[celli] = sigmaTcR;
362 if ((sigmaTcR/sigmaTcRMax) > rndGen_.scalar01())
364 binaryCollision().collide
376 reduce(collisions, sumOp<label>());
378 reduce(collisionCandidates, sumOp<label>());
380 sigmaTcRMax_.correctBoundaryConditions();
382 if (collisionCandidates)
384 Info<<
" Collisions = "
386 <<
" Acceptance rate = "
387 << scalar(collisions)/scalar(collisionCandidates) <<
nl
397 template<
class ParcelType>
405 dimensionSet(1, -1, -2, 0, 0),
419 dimensionSet(1, -2, -1, 0, 0),
425 template<
class ParcelType>
430 scalarField& dsmcRhoN = dsmcRhoN_.primitiveFieldRef();
431 scalarField& linearKE = linearKE_.primitiveFieldRef();
432 scalarField& internalE = internalE_.primitiveFieldRef();
438 const ParcelType&
p = iter();
439 const label celli =
p.cell();
442 rhoM[celli] += constProps(
p.typeId()).mass();
444 linearKE[celli] += 0.5*constProps(
p.typeId()).mass()*(
p.U() &
p.U());
445 internalE[celli] +=
p.Ei();
446 iDof[celli] += constProps(
p.typeId()).internalDegreesOfFreedom();
447 momentum[celli] += constProps(
p.typeId()).mass()*
p.U();
451 rhoN_.correctBoundaryConditions();
454 rhoM_.correctBoundaryConditions();
456 dsmcRhoN_.correctBoundaryConditions();
459 linearKE_.correctBoundaryConditions();
462 internalE_.correctBoundaryConditions();
465 iDof_.correctBoundaryConditions();
468 momentum_.correctBoundaryConditions();
474 template<
class ParcelType>
480 label& nLocateBoundaryHits,
504 template<
class ParcelType>
520 mesh_.
time().constant(),
526 typeIdList_(particleProperties_.
lookup(
"typeIdList")),
529 particleProperties_.template
lookup<scalar>(
"nEquivalentParticles")
531 cellOccupancy_(mesh_.nCells()),
536 this->
name() +
"SigmaTcRMax",
544 collisionSelectionRemainder_
548 this->
name() +
":collisionSelectionRemainder",
664 rndGen_(
label(149382906)),
665 stdNormal_(rndGen_.generator()),
696 binaryCollisionModel_
704 wallInteractionModel_
722 buildCellOccupancy();
726 forAll(collisionSelectionRemainder_, i)
728 collisionSelectionRemainder_[i] = rndGen_.
scalar01();
738 template<
class ParcelType>
754 mesh_.
time().constant(),
760 typeIdList_(particleProperties_.
lookup(
"typeIdList")),
763 particleProperties_.template
lookup<scalar>(
"nEquivalentParticles")
770 this->
name() +
"SigmaTcRMax",
778 zeroGradientFvPatchScalarField::
typeName
780 collisionSelectionRemainder_
784 this->
name() +
":collisionSelectionRemainder",
808 this->
name() +
"fD_",
826 this->
name() +
"rhoN_",
839 this->
name() +
"rhoM_",
852 this->
name() +
"dsmcRhoN_",
865 this->
name() +
"linearKE_",
878 this->
name() +
"internalE_",
891 this->
name() +
"iDof_",
904 this->
name() +
"momentum_",
919 rndGen_(
label(971501)),
920 stdNormal_(rndGen_.generator()),
958 binaryCollisionModel_(),
959 wallInteractionModel_(),
960 inflowBoundaryModel_()
964 initialise(dsmcInitialiseDict);
970 template<
class ParcelType>
977 template<
class ParcelType>
980 typename ParcelType::trackingData td(*
this);
987 this->dumpParticlePositions();
991 this->inflowBoundary().inflow();
997 buildCellOccupancy();
1007 template<
class ParcelType>
1010 label nDSMCParticles = this->size();
1013 scalar nMol = nDSMCParticles*nParticle_;
1015 vector linearMomentum = linearMomentumOfSystem();
1018 scalar linearKineticEnergy = linearKineticEnergyOfSystem();
1021 scalar internalEnergy = internalEnergyOfSystem();
1025 <<
" Number of dsmc particles = "
1031 Info<<
" Number of molecules = "
1033 <<
" Mass in system = "
1035 <<
" Average linear momentum = "
1036 << linearMomentum/nMol <<
nl
1037 <<
" |Average linear momentum| = "
1038 <<
mag(linearMomentum)/nMol <<
nl
1039 <<
" Average linear kinetic energy = "
1040 << linearKineticEnergy/nMol <<
nl
1041 <<
" Average internal energy = "
1042 << internalEnergy/nMol <<
nl
1043 <<
" Average total energy = "
1044 << (internalEnergy + linearKineticEnergy)/nMol
1050 template<
class ParcelType>
1059 *stdNormal_.sample<
vector>();
1063 template<
class ParcelType>
1083 scalar a = 0.5*iDof - 1;
1089 energyRatio = 10*rndGen_.scalar01();
1090 P =
pow((energyRatio/a), a)*
exp(a - energyRatio);
1091 }
while (P < rndGen_.scalar01());
1100 template<
class ParcelType>
1105 this->
time().path()/
"parcelPositions_"
1106 + this->
name() +
"_"
1114 pObj<<
"v " <<
pos.x() <<
" " <<
pos.y() <<
" " <<
pos.z() <<
nl;
1121 template<
class ParcelType>
1127 cellOccupancy_.setSize(mesh_.nCells());
1128 buildCellOccupancy();
1131 this->inflowBoundary().topoChange();
1135 template<
class ParcelType>
1141 cellOccupancy_.setSize(mesh_.nCells());
1142 buildCellOccupancy();
1145 this->inflowBoundary().topoChange();
1149 template<
class ParcelType>
1155 cellOccupancy_.setSize(mesh_.nCells());
1156 buildCellOccupancy();
1159 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.
Templated base class for dsmc cloud.
void addNewParcel(const meshSearch &searchEngine, 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.
scalar deltaTValue() const
Return time step value.
Templated wall interaction model class.
Dimension set for the base types.
Mesh data needed to do the Finite Volume discretisation.
const Time & time() const
Return the top-level database.
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.
Mesh object that implements searches within the local cells and faces.
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Motion of the mesh specified as a list of pointMeshMovers.
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.
const scalarField & cellVolumes() const
scalar scalar01()
Return a scalar uniformly distributed between zero and one.
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A class for handling words, derived from string.
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#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.
const dimensionSet velocity
const dimensionSet temperature
const dimensionSet momentum
point position(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label facei, const label faceTrii, const scalar stepFraction)
Return the position given the coordinates and tet topology.
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
dimensionedScalar pos(const dimensionedScalar &ds)
dimensionedScalar exp(const dimensionedScalar &ds)
const dimensionSet & dimless
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.
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)
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)
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)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Field< vector > vectorField
Specialisation of Field<T> for vector.
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< typename powProduct< Type, r >::type, GeoMesh, Field > > pow(const DimensionedField< Type, GeoMesh, PrimitiveField > &df, typename powProduct< Type, r >::type)
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
void sqrt(LagrangianPatchField< scalar > &f, const LagrangianPatchField< scalar > &f1)
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tetrahedron< point, const point & > tetPointRef
const word cloudName(propsDict.lookup("cloudName"))