34 template<
class CloudType>
41 if (
dict.found(
"nParticle"))
43 if (
dict.found(
"massTotal"))
46 <<
"If nParticle is specified then the massTotal "
47 <<
"setting has no effect " <<
endl;
53 if (owner.solution().steadyState())
56 <<
"The " <<
type() <<
" injection model is not compatible with "
57 <<
"steady state solution"
67 template<
class CloudType>
74 if (owner.solution().steadyState())
83 template<
class CloudType>
92 const bool haveMassFlowRate =
dict.found(
"massFlowRate");
93 const bool haveMassTotal =
dict.found(
"massTotal");
95 if (
dict.found(
"nParticle"))
97 if (haveMassFlowRate || haveMassTotal)
100 <<
"If nParticle is specified then massFlowRate and massTotal "
101 <<
"settings have no effect " <<
endl;
111 if (owner.solution().steadyState() && haveMassTotal)
114 <<
"Cannot specify the massTotal of a steady injection. Use "
118 if (haveMassFlowRate && haveMassTotal)
121 <<
"Cannot specify both massFlowRate and massTotal. Use one or "
125 if (owner.solution().steadyState())
138 if (haveMassFlowRate)
144 this->owner().
time().userUnits(),
150 const scalar massTotal =
dict.lookup<scalar>(
"massTotal",
dimMass);
152 if (!
dict.found(
"flowRateProfile"))
170 this->owner().
time().userUnits(),
176 const scalar sumFlowRateProfile = flowRateProfile->integral(0, duration);
192 template<
class CloudType>
204 this->owner().
time().userUnits(),
211 template<
class CloudType>
214 forAll(this->owner().injectors(), i)
216 if (this->owner().injectors()(i) ==
this)
226 template<
class CloudType>
239 auto findProcAndCell = [
this,&searchEngine](
const point&
pos)
245 label proci = celli >= 0 ? Pstream::myProcNo() : -1;
247 if (proci != Pstream::myProcNo())
260 celli = procAndCelli.
second();
266 pos += small*(this->owner().mesh().C()[celli] -
pos);
268 proci = procAndCelli.first();
269 celli = procAndCelli.second();
278 <<
"Cannot find parcel injection cell. "
287 if (proci == Pstream::myProcNo())
289 label nLocateBoundaryHits = 0;
290 particle p(searchEngine,
pos, celli, nLocateBoundaryHits);
292 if (nLocateBoundaryHits != 0)
295 <<
"Injection model " << this->
modelName()
296 <<
" for cloud " << this->owner().name()
297 <<
" did not accurately locate the position "
298 <<
pos <<
" within the mesh" <<
endl;
303 tetFacei =
p.tetFace();
311 template<
class CloudType>
314 typename CloudType::parcelType::trackingData& td,
318 const vector d = parcel.deviationFromMeshCentre(td.mesh);
320 if (d == vector::zero)
325 const label facei = parcel.face();
330 parcel.track(td.mesh, - d, 0);
339 td.mesh.cellCentres()[parcel.cell()] - parcel.position(td.mesh);
341 parcel.track(td.mesh, - d/2 + rootSmall*pc, 0);
342 parcel.track(td.mesh, - d/2 - rootSmall*pc, 0);
346 parcel.face() = facei;
350 template<
class CloudType>
353 switch (uniformParcelSize_)
355 case uniformParcelSize::nParticle:
357 case uniformParcelSize::surfaceArea:
367 template<
class CloudType>
376 switch (uniformParcelSize_)
378 case uniformParcelSize::nParticle:
380 case uniformParcelSize::surfaceArea:
389 scalar sumMassBySize = 0;
390 forAll(parcelPtrs, parceli)
392 if (parcelPtrs.
set(parceli))
395 sumMassBySize +=
p.mass()/size(
p);
402 forAll(parcelPtrs, parceli)
404 if (parcelPtrs.
set(parceli))
407 p.nParticle() =
mass/size(
p)/sumMassBySize;
414 scalar massN = 0, minSizeN = vGreat, maxSizeN = -vGreat;
415 forAll(parcelPtrs, parceli)
417 if (parcelPtrs.
set(parceli))
420 massN +=
p.nParticle()*
p.mass();
421 minSizeN =
min(minSizeN,
p.nParticle()*size(
p));
422 maxSizeN =
max(minSizeN,
p.nParticle()*size(
p));
428 if (
mag(massN -
mass) > rootSmall*(massN +
mass)/2)
431 <<
"Parcels do not have the required mass"
438 if (maxSizeN - minSizeN > rootSmall*(maxSizeN + minSizeN)/2)
441 <<
"Parcel sizes are not uniform"
448 template<
class CloudType>
451 typename parcelType::trackingData& td
456 template<
class CloudType>
459 const label nParcelsAdded,
460 const scalar massAdded,
461 typename parcelType::trackingData& td
466 if (allNParcelsAdded > 0)
469 <<
"Cloud: " << this->owner().name()
471 <<
" Added " << allNParcelsAdded <<
" new parcels" <<
nl <<
endl;
475 nParcelsInjected_ += allNParcelsAdded;
484 template<
class CloudType>
489 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
492 this->template getModelProperty<scalar>(
"nParcelsInjected")
496 this->template getModelProperty<scalar>(
"massDeferred")
500 this->template getModelProperty<scalar>(
"nParcelsDeferred")
502 nParticleFixed_(-vGreat),
507 template<
class CloudType>
513 const word& modelType
518 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
521 this->template getModelProperty<scalar>(
"nParcelsInjected")
525 this->template getModelProperty<scalar>(
"massDeferred")
529 this->template getModelProperty<scalar>(
"nParcelsDeferred")
531 nParticleFixed_(
dict.lookupOrDefault<scalar>(
"nParticle", -vGreat)),
534 uniformParcelSizeNames_
536 !
dict.
found(
"parcelBasisType") && nParticleFixed_ > 0
559 <<
"If nParticle is specified then the uniformParcelSize must be "
564 if (
owner.solution().transient())
571 template<
class CloudType>
579 massInjected_(im.massInjected_),
580 nParcelsInjected_(im.nParcelsInjected_),
581 massDeferred_(im.massDeferred_),
582 nParcelsDeferred_(im.nParcelsDeferred_),
583 nParticleFixed_(im.nParticleFixed_),
584 uniformParcelSize_(im.uniformParcelSize_)
590 template<
class CloudType>
597 template<
class CloudType>
602 template<
class CloudType>
605 const scalar deltaT =
606 this->owner().solution().transient() ? timeEnd() - timeStart() : 1;
608 return massToInject(0, deltaT)/nParcelsToInject(0, deltaT);
612 template<
class CloudType>
613 template<
class TrackCloudType>
616 TrackCloudType&
cloud,
617 typename CloudType::parcelType::trackingData& td
624 const scalar time1 = this->owner().time().value();
626 this->owner().time().value()
627 - this->owner().time().deltaTValue();
632 label nParcelsAdded = 0;
633 scalar massAdded = 0;
640 const scalar t0 = time0 - SOI_, t1 = time1 - SOI_;
644 const scalar nParcelsNoRound =
645 nParcelsToInject(t0, t1) + nParcelsDeferred_;
646 nParcels = floor(nParcelsNoRound);
647 nParcelsDeferred_ = nParcelsNoRound - nParcels;
650 if (nParticleFixed_ < 0)
654 mass = massToInject(t0, t1) + massDeferred_;
655 massDeferred_ = nParcels > 0 ? 0 :
mass;
665 nParcelsDeferred_ = 0;
674 const scalar deltaT =
690 const scalar padTime =
max(scalar(0), SOI_ - time0);
694 forAll(parcelPtrs, parceli)
697 scalar timeInj = time0 + padTime + deltaT*parceli/nParcels;
702 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
719 const scalar dt = timeInj - time0;
738 constrainPosition(td,
p);
741 cloud.setParcelThermoProperties(
p);
744 setProperties(parceli, nParcels, timeInj, td,
p);
747 cloud.checkParcelProperties(
p, index());
759 p.stepFraction() = dt/td.trackTime();
763 p.nParticle() = nParticleFixed_;
769 if (nParticleFixed_ < 0)
771 setNumberOfParticles(parcelPtrs,
mass);
775 forAll(parcelPtrs, parceli)
777 if (parcelPtrs.
set(parceli))
781 massAdded +=
p.nParticle()*
p.mass();
782 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
787 postInject(nParcelsAdded, massAdded, td);
791 template<
class CloudType>
792 template<
class TrackCloudType>
795 TrackCloudType&
cloud,
796 typename CloudType::parcelType::trackingData& td
806 label nParcelsAdded = 0;
807 scalar massAdded = 0;
810 const label nParcels = floor(nParcelsToInject(0, 1));
811 const scalar
mass = nParticleFixed_ < 0 ? massToInject(0, 1) : NaN;
817 forAll(parcelPtrs, parceli)
822 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
855 constrainPosition(td,
p);
858 cloud.setParcelThermoProperties(
p);
861 setProperties(parceli, nParcels, 0, td,
p);
864 cloud.checkParcelProperties(
p, index());
870 p.stepFraction() = 0;
874 p.nParticle() = nParticleFixed_;
880 if (nParticleFixed_ < 0)
882 setNumberOfParticles(parcelPtrs,
mass);
886 forAll(parcelPtrs, parceli)
888 if (parcelPtrs.
set(parceli))
892 massAdded +=
p.nParticle()*
p.mass();
893 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
898 postInject(nParcelsAdded, massAdded, td);
902 template<
class CloudType>
906 <<
" number of parcels added = " << nParcelsInjected_ <<
nl
907 <<
" mass introduced = " << massInjected_ <<
nl;
909 if (this->writeTime())
911 this->setModelProperty(
"massInjected", massInjected_);
912 this->setModelProperty(
"nParcelsInjected", nParcelsInjected_);
913 this->setModelProperty(
"massDeferred", massDeferred_);
914 this->setModelProperty(
"nParcelsDeferred", nParcelsDeferred_);
#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.
Run-time selectable general function of one variable.
Function1 which scales a given 'value' function by a 'scale' scalar function and scales the 'x' argum...
Templated injection model class.
virtual void topoChange()
Update mesh.
virtual ~InjectionModel()
Destructor.
void inject(TrackCloudType &cloud, typename CloudType::parcelType::trackingData &td)
Main injection loop.
autoPtr< Function1< scalar > > readParcelsPerSecond(const dictionary &dict, CloudType &owner)
Read the number of parcels injected per second for continuous.
void constrainPosition(typename CloudType::parcelType::trackingData &td, typename CloudType::parcelType &parcel)
Constrain a parcel's position appropriately to the geometric.
virtual void postInject(const label parcelsAdded, const scalar massAdded, typename parcelType::trackingData &td)
Post injection hook.
virtual void preInject(typename parcelType::trackingData &td)
Pre injection hook.
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.
autoPtr< Function1< scalar > > readMassFlowRate(const dictionary &dict, CloudType &owner, const scalar duration)
Read the mass flow rate function for continuous injections.
uniformParcelSize uniformParcelSize_
Size uniform to all parcels.
label sizeSampleQ() const
Return the sampling moment to be used by the size distribution.
bool findCellAtPosition(const meshSearch &searchEngine, const point &position, barycentric &coordinates, label &celli, label &tetFacei, label &tetPti, bool errorOnNotFound=true)
Find the cell that contains the supplied position.
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.
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.
CloudType::parcelType parcelType
Convenience typedef for parcelType.
scalar SOI_
Start of injection [s].
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.
const unitSet & userUnits() const
Return the user-time unit conversion.
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...
Base class for clouds. Provides a basic evolution algorithm, models, and a database for caching deriv...
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
uniformParcelSize
Enumeration for the parcels' uniform size.
static const NamedEnum< uniformParcelSize, 3 > uniformParcelSizeNames_
Names of the parcels' uniform size.
Mesh object that implements searches within the local cells and faces.
label findCell(const point &p, const pointInCellShapes=pointInCellShapes::tets) const
Find the cell containing the given point.
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
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 & dict() const
Return const access to the cloud dictionary.
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 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.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionSet dimless
const dimensionSet volume
barycentric coordinates(const polyMesh &mesh, const point &position, const label celli, const label facei, const label faceTrii, const scalar stepFraction)
Return the coordinates given the position and tet topology.
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.
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.
const dimensionSet & dimMass
Ostream & endl(Ostream &os)
Add newline and flush stream.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
const dimensionSet & dimTime
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
static const label labelMax
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.