36 template<
class CloudType>
43 if (
dict.found(
"nParticle"))
45 if (
dict.found(
"massTotal"))
48 <<
"If nParticle is specified then the massTotal "
49 <<
"setting has no effect " <<
endl;
55 if (owner.solution().steadyState())
58 <<
"The " <<
type() <<
" injection model is not compatible with "
59 <<
"steady state solution"
65 return dict.lookup<scalar>(
"massTotal");
69 template<
class CloudType>
78 if (owner.solution().steadyState())
86 this->coeffDict().
template lookup<scalar>(
"duration")
91 template<
class CloudType>
102 const bool haveMassFlowRate =
dict.found(
"massFlowRate");
103 const bool haveMassTotal =
dict.found(
"massTotal");
105 if (
dict.found(
"nParticle"))
107 if (haveMassFlowRate || haveMassTotal)
110 <<
"If nParticle is specified then massFlowRate and massTotal "
111 <<
"settings have no effect " <<
endl;
122 if (owner.solution().steadyState() && haveMassTotal)
125 <<
"Cannot specify the massTotal of a steady injection. Use "
129 if (haveMassFlowRate && haveMassTotal)
132 <<
"Cannot specify both massFlowRate and massTotal. Use one or "
136 if (owner.solution().steadyState() || haveMassFlowRate)
141 const scalar massTotal =
dict.lookup<scalar>(
"massTotal");
143 if (!
dict.found(
"flowRateProfile"))
156 const scalar sumFlowRateProfile = flowRateProfile->integral(0, duration);
173 template<
class CloudType>
187 template<
class CloudType>
190 forAll(this->owner().injectors(), i)
192 if (this->owner().injectors()(i) ==
this)
202 template<
class CloudType>
205 const point& position,
214 auto findProcAndCell = [
this](
const point&
pos)
217 label celli = this->owner().mesh().findCell(
pos);
235 celli = procAndCelli.
second();
241 pos += small*(this->owner().mesh().C()[celli] -
pos);
243 proci = procAndCelli.first();
244 celli = procAndCelli.second();
253 <<
"Cannot find parcel injection cell. "
254 <<
"Parcel position = " << position <<
nl
265 coordinates =
p.coordinates();
267 tetFacei =
p.tetFace();
275 template<
class CloudType>
278 typename CloudType::parcelType::trackingData& td,
282 const vector d = parcel.deviationFromMeshCentre(td.mesh);
289 const label facei = parcel.face();
294 parcel.track(td.mesh, - d, 0);
303 td.mesh.cellCentres()[parcel.cell()] - parcel.position(td.mesh);
305 parcel.track(td.mesh, - d/2 + rootSmall*pc, 0);
306 parcel.track(td.mesh, - d/2 - rootSmall*pc, 0);
310 parcel.face() = facei;
314 template<
class CloudType>
317 switch (uniformParcelSize_)
319 case uniformParcelSize::nParticle:
321 case uniformParcelSize::surfaceArea:
323 case uniformParcelSize::volume:
331 template<
class CloudType>
340 switch (uniformParcelSize_)
342 case uniformParcelSize::nParticle:
344 case uniformParcelSize::surfaceArea:
346 case uniformParcelSize::volume:
353 scalar sumMassBySize = 0;
354 forAll(parcelPtrs, parceli)
356 if (parcelPtrs.
set(parceli))
359 sumMassBySize +=
p.mass()/size(
p);
366 forAll(parcelPtrs, parceli)
368 if (parcelPtrs.
set(parceli))
371 p.nParticle() = mass/size(
p)/sumMassBySize;
378 scalar massN = 0, minSizeN = vGreat, maxSizeN = -vGreat;
379 forAll(parcelPtrs, parceli)
381 if (parcelPtrs.
set(parceli))
384 massN +=
p.nParticle()*
p.mass();
385 minSizeN =
min(minSizeN,
p.nParticle()*size(
p));
386 maxSizeN =
max(minSizeN,
p.nParticle()*size(
p));
392 if (
mag(massN - mass) > rootSmall*(massN + mass)/2)
395 <<
"Parcels do not have the required mass"
402 if (maxSizeN - minSizeN > rootSmall*(maxSizeN + minSizeN)/2)
405 <<
"Parcel sizes are not uniform"
412 template<
class CloudType>
415 const label nParcelsAdded,
416 const scalar massAdded
421 if (allNParcelsAdded > 0)
424 <<
"Cloud: " << this->owner().name()
425 <<
" injector: " << this->modelName() <<
nl
426 <<
" Added " << allNParcelsAdded <<
" new parcels" <<
nl <<
endl;
430 parcelsAddedTotal_ += allNParcelsAdded;
436 time0_ = this->owner().db().time().value();
445 template<
class CloudType>
450 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
451 nInjections_(this->template getModelProperty<
label>(
"nInjections")),
454 this->template getModelProperty<scalar>(
"parcelsAddedTotal")
456 nParticleFixed_(-vGreat),
459 timeStep0_(this->template getModelProperty<scalar>(
"timeStep0"))
463 template<
class CloudType>
468 const word& modelName,
469 const word& modelType
474 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
475 nInjections_(this->template getModelProperty<scalar>(
"nInjections")),
478 this->template getModelProperty<scalar>(
"parcelsAddedTotal")
480 nParticleFixed_(
dict.lookupOrDefault<scalar>(
"nParticle", -vGreat)),
483 uniformParcelSizeNames_
485 !
dict.
found(
"parcelBasisType") && nParticleFixed_ > 0
491 :
dict.lookup<
word>(
"uniformParcelSize")
494 time0_(owner.db().time().value()),
495 timeStep0_(this->template getModelProperty<scalar>(
"timeStep0"))
510 <<
"If nParticle is specified then the uniformParcelSize must be "
515 if (
owner.solution().transient())
520 this->
coeffDict().
template lookup<scalar>(
"SOI")
526 template<
class CloudType>
534 massInjected_(im.massInjected_),
535 nInjections_(im.nInjections_),
536 parcelsAddedTotal_(im.parcelsAddedTotal_),
537 nParticleFixed_(im.nParticleFixed_),
538 uniformParcelSize_(im.uniformParcelSize_),
540 timeStep0_(im.timeStep0_)
546 template<
class CloudType>
553 template<
class CloudType>
558 template<
class CloudType>
561 const scalar deltaT =
562 this->owner().solution().transient() ? timeEnd() - timeStart() : 1;
564 return massToInject(0, deltaT)/nParcelsToInject(0, deltaT);
568 template<
class CloudType>
569 template<
class TrackCloudType>
572 TrackCloudType&
cloud,
573 typename CloudType::parcelType::trackingData& td
576 const polyMesh& mesh = this->owner().mesh();
578 const scalar time = this->owner().
db().
time().
value();
581 label nParcelsAdded = 0;
582 scalar massAdded = 0;
599 const scalar t0 = timeStep0_ - SOI_, t1 = time - SOI_;
600 nParcels = nParcelsToInject(t0, t1);
601 mass = nParticleFixed_ < 0 ? massToInject(t0, t1) :
NaN;
603 if (nParcels > 0 && (nParticleFixed_ > 0 || mass > 0))
609 else if (nParcels == 0 && (nParticleFixed_ < 0 && mass > 0))
629 const scalar deltaT =
645 const scalar padTime =
max(scalar(0), SOI_ - time0_);
649 forAll(parcelPtrs, parceli)
652 scalar timeInj = time0_ + padTime + deltaT*parceli/nParcels;
657 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
673 const scalar dt = timeInj - time0_;
692 constrainPosition(td,
p);
695 cloud.setParcelThermoProperties(
p);
698 setProperties(parceli, nParcels, timeInj,
p);
701 cloud.checkParcelProperties(
p, index());
713 p.stepFraction() = dt/td.trackTime();
717 p.nParticle() = nParticleFixed_;
723 if (nParticleFixed_ < 0)
725 setNumberOfParticles(parcelPtrs, mass);
729 forAll(parcelPtrs, parceli)
731 if (parcelPtrs.
set(parceli))
735 massAdded +=
p.nParticle()*
p.mass();
736 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
741 postInjectCheck(nParcelsAdded, massAdded);
745 template<
class CloudType>
746 template<
class TrackCloudType>
749 TrackCloudType&
cloud,
750 typename CloudType::parcelType::trackingData& td
753 const polyMesh& mesh = this->owner().mesh();
756 label nParcelsAdded = 0;
757 scalar massAdded = 0;
760 const label nParcels = nParcelsToInject(0, 1);
761 const scalar mass = nParticleFixed_ < 0 ? massToInject(0, 1) :
NaN;
767 forAll(parcelPtrs, parceli)
772 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
804 constrainPosition(td,
p);
807 cloud.setParcelThermoProperties(
p);
810 setProperties(parceli, nParcels, 0,
p);
813 cloud.checkParcelProperties(
p, index());
819 p.stepFraction() = 0;
823 p.nParticle() = nParticleFixed_;
829 if (nParticleFixed_ < 0)
831 setNumberOfParticles(parcelPtrs, mass);
835 forAll(parcelPtrs, parceli)
837 if (parcelPtrs.
set(parceli))
841 massAdded +=
p.nParticle()*
p.mass();
842 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
847 postInjectCheck(nParcelsAdded, massAdded);
851 template<
class CloudType>
854 os <<
" " << this->modelName() <<
":" <<
nl
855 <<
" number of parcels added = " << parcelsAddedTotal_ <<
nl
856 <<
" mass introduced = " << massInjected_ <<
nl;
858 if (this->writeTime())
860 this->setModelProperty(
"massInjected", massInjected_);
861 this->setModelProperty(
"nInjections", nInjections_);
862 this->setModelProperty(
"parcelsAddedTotal", parcelsAddedTotal_);
863 this->setModelProperty(
"timeStep0", timeStep0_);
#define forAll(list, i)
Loop across all elements in list.
Base class for cloud sub-models.
const CloudType & owner() const
Return const access to the owner cloud.
Templated base class for dsmc cloud.
ParcelType parcelType
Type of parcel the cloud was instantiated for.
const fvMesh & mesh() const
Return references to the mesh.
static autoPtr< Function1< Type > > New(const word &name, const dictionary &dict)
Selector.
Templated function that returns a constant value.
Function1 which scales a given 'value' function by a 'scale' scalar function and scales the 'x' argum...
const objectRegistry & db() const
Return the local objectRegistry.
Templated injection model class.
virtual void topoChange()
Update mesh.
virtual ~InjectionModel()
Destructor.
void inject(TrackCloudType &cloud, typename CloudType::parcelType::trackingData &td)
Main injection loop.
void constrainPosition(typename CloudType::parcelType::trackingData &td, typename CloudType::parcelType &parcel)
Constrain a parcel's position appropriately to the geometric.
bool findCellAtPosition(const point &position, barycentric &coordinates, label &celli, label &tetFacei, label &tetPti, bool errorOnNotFound=true)
Find the cell that contains the supplied position.
scalar readMassTotal(const dictionary &dict, CloudType &owner)
Read the total mass value for instantaneous injections.
virtual void info(Ostream &os)
Write injection info to stream.
void setNumberOfParticles(PtrList< parcelType > &parcelPtrs, const scalar mass) const
Set number of particles to inject given parcel properties.
uniformParcelSize uniformParcelSize_
Size uniform to all parcels.
label sizeSampleQ() const
Return the sampling moment to be used by the size distribution.
scalar averageParcelMass()
Return the average injected parcel mass.
scalar nParticleFixed_
Fixed nParticle to assign to parcels. Only valid if.
label index() const
Get the index of this injector.
TimeFunction1< scalar > readParcelsPerSecond(const dictionary &dict, CloudType &owner)
Read the number of parcels injected per second for continuous.
void injectSteadyState(TrackCloudType &cloud, typename CloudType::parcelType::trackingData &td)
Main injection loop - steady-state.
scalar readDuration(const dictionary &dict, CloudType &owner)
Read the duration for continuous injections.
InjectionModel(CloudType &owner)
Construct null from owner.
TimeFunction1< scalar > readMassFlowRate(const dictionary &dict, CloudType &owner, const scalar duration)
Read the mass flow rate function for continuous injections.
CloudType::parcelType parcelType
Convenience typedef for parcelType.
scalar SOI_
Start of injection [s].
void postInjectCheck(const label parcelsAdded, const scalar massAdded)
Post injection checks.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
const Type & second() const
Return second.
const Type & first() const
Return first.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
bool set(const label) const
Is element set.
Light wrapper around Function1 to provide a mechanism to update time-based entries.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
scalar userTimeToTime(const scalar tau) const
Convert the user-time (e.g. CA deg) to real-time (s).
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
static Form uniform(const Cmpt &s)
Return a VectorSpace with all elements = s.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
A cloud is a collection of lagrangian particles.
A list of keyword definitions, which are a keyword followed by any number of values (e....
const Type & value() const
Return const reference to value.
const Time & time() const
Return the top-level database.
uniformParcelSize
Enumeration for the parcels' uniform size.
static const NamedEnum< uniformParcelSize, 3 > uniformParcelSizeNames_
Names of the parcels' uniform size.
const Time & time() const
Return time.
Mesh consisting of general polyhedral cells.
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
const Vector< label > & solutionD() const
Return the vector of solved-for directions in mesh.
const dictionary & coeffDict() const
Return const access to the coefficients dictionary.
const dictionary & dict() const
Return const access to the cloud dictionary.
A class for handling words, derived from string.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensionedScalar pos(const dimensionedScalar &ds)
Pair< label > labelPair
Label pair.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Ostream & endl(Ostream &os)
Add newline and flush stream.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
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< scalar > mag(const dimensioned< Type > &)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
static const label labelMax
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.