33 template<
class CloudType>
40 if (
dict.found(
"nParticle"))
42 if (
dict.found(
"massTotal"))
45 <<
"If nParticle is specified then the massTotal "
46 <<
"setting has no effect " <<
endl;
52 if (owner.solution().steadyState())
55 <<
"The " <<
type() <<
" injection model is not compatible with "
56 <<
"steady state solution"
66 template<
class CloudType>
73 if (owner.solution().steadyState())
82 template<
class CloudType>
91 const bool haveMassFlowRate =
dict.found(
"massFlowRate");
92 const bool haveMassTotal =
dict.found(
"massTotal");
94 if (
dict.found(
"nParticle"))
96 if (haveMassFlowRate || haveMassTotal)
99 <<
"If nParticle is specified then massFlowRate and massTotal "
100 <<
"settings have no effect " <<
endl;
110 if (owner.solution().steadyState() && haveMassTotal)
113 <<
"Cannot specify the massTotal of a steady injection. Use "
117 if (haveMassFlowRate && haveMassTotal)
120 <<
"Cannot specify both massFlowRate and massTotal. Use one or "
124 if (owner.solution().steadyState() || haveMassFlowRate)
130 this->owner().db().time().userUnits(),
136 const scalar massTotal =
dict.lookup<scalar>(
"massTotal",
dimMass);
138 if (!
dict.found(
"flowRateProfile"))
156 this->owner().db().time().userUnits(),
162 const scalar sumFlowRateProfile = flowRateProfile->integral(0, duration);
178 template<
class CloudType>
190 this->owner().db().time().userUnits(),
197 template<
class CloudType>
200 forAll(this->owner().injectors(), i)
202 if (this->owner().injectors()(i) ==
this)
212 template<
class CloudType>
215 const point& position,
224 auto findProcAndCell = [
this](
const point&
pos)
227 label celli = this->owner().mesh().findCell(
pos);
230 label proci = celli >= 0 ? Pstream::myProcNo() : -1;
232 if (proci != Pstream::myProcNo())
245 celli = procAndCelli.
second();
251 pos += small*(this->owner().mesh().C()[celli] -
pos);
253 proci = procAndCelli.first();
254 celli = procAndCelli.second();
263 <<
"Cannot find parcel injection cell. "
264 <<
"Parcel position = " << position <<
nl
272 if (proci == Pstream::myProcNo())
274 label nLocateBoundaryHits = 0;
275 particle p(this->owner().mesh(),
pos, celli, nLocateBoundaryHits);
277 if (nLocateBoundaryHits != 0)
280 <<
"Injection model " << this->modelName()
281 <<
" for cloud " << this->owner().name()
282 <<
" did not accurately locate the position "
283 <<
pos <<
" within the mesh" <<
endl;
286 coordinates =
p.coordinates();
288 tetFacei =
p.tetFace();
296 template<
class CloudType>
299 typename CloudType::parcelType::trackingData& td,
303 const vector d = parcel.deviationFromMeshCentre(td.mesh);
305 if (d == vector::zero)
310 const label facei = parcel.face();
315 parcel.track(td.mesh, - d, 0);
324 td.mesh.cellCentres()[parcel.cell()] - parcel.position(td.mesh);
326 parcel.track(td.mesh, - d/2 + rootSmall*pc, 0);
327 parcel.track(td.mesh, - d/2 - rootSmall*pc, 0);
331 parcel.face() = facei;
335 template<
class CloudType>
338 switch (uniformParcelSize_)
340 case uniformParcelSize::nParticle:
342 case uniformParcelSize::surfaceArea:
344 case uniformParcelSize::volume:
352 template<
class CloudType>
361 switch (uniformParcelSize_)
363 case uniformParcelSize::nParticle:
365 case uniformParcelSize::surfaceArea:
367 case uniformParcelSize::volume:
374 scalar sumMassBySize = 0;
375 forAll(parcelPtrs, parceli)
377 if (parcelPtrs.
set(parceli))
380 sumMassBySize +=
p.mass()/size(
p);
387 forAll(parcelPtrs, parceli)
389 if (parcelPtrs.
set(parceli))
392 p.nParticle() = mass/size(
p)/sumMassBySize;
399 scalar massN = 0, minSizeN = vGreat, maxSizeN = -vGreat;
400 forAll(parcelPtrs, parceli)
402 if (parcelPtrs.
set(parceli))
405 massN +=
p.nParticle()*
p.mass();
406 minSizeN =
min(minSizeN,
p.nParticle()*size(
p));
407 maxSizeN =
max(minSizeN,
p.nParticle()*size(
p));
413 if (
mag(massN - mass) > rootSmall*(massN + mass)/2)
416 <<
"Parcels do not have the required mass"
423 if (maxSizeN - minSizeN > rootSmall*(maxSizeN + minSizeN)/2)
426 <<
"Parcel sizes are not uniform"
433 template<
class CloudType>
436 typename parcelType::trackingData& td
441 template<
class CloudType>
444 const label nParcelsAdded,
445 const scalar massAdded,
446 typename parcelType::trackingData& td
451 if (allNParcelsAdded > 0)
454 <<
"Cloud: " << this->owner().name()
455 <<
" injector: " << this->modelName() <<
nl
456 <<
" Added " << allNParcelsAdded <<
" new parcels" <<
nl <<
endl;
460 parcelsAddedTotal_ += allNParcelsAdded;
466 time0_ = this->owner().db().time().value();
475 template<
class CloudType>
480 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
481 nInjections_(this->template getModelProperty<
label>(
"nInjections")),
484 this->template getModelProperty<scalar>(
"parcelsAddedTotal")
486 nParticleFixed_(-vGreat),
489 timeStep0_(this->template getModelProperty<scalar>(
"timeStep0"))
493 template<
class CloudType>
498 const word& modelName,
499 const word& modelType
504 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
505 nInjections_(this->template getModelProperty<scalar>(
"nInjections")),
508 this->template getModelProperty<scalar>(
"parcelsAddedTotal")
510 nParticleFixed_(
dict.lookupOrDefault<scalar>(
"nParticle", -vGreat)),
513 uniformParcelSizeNames_
515 !
dict.
found(
"parcelBasisType") && nParticleFixed_ > 0
521 :
dict.lookup<
word>(
"uniformParcelSize")
524 time0_(owner.db().time().value()),
525 timeStep0_(this->template getModelProperty<scalar>(
"timeStep0"))
540 <<
"If nParticle is specified then the uniformParcelSize must be "
545 if (
owner.solution().transient())
552 template<
class CloudType>
560 massInjected_(im.massInjected_),
561 nInjections_(im.nInjections_),
562 parcelsAddedTotal_(im.parcelsAddedTotal_),
563 nParticleFixed_(im.nParticleFixed_),
564 uniformParcelSize_(im.uniformParcelSize_),
566 timeStep0_(im.timeStep0_)
572 template<
class CloudType>
579 template<
class CloudType>
584 template<
class CloudType>
587 const scalar deltaT =
588 this->owner().solution().transient() ? timeEnd() - timeStart() : 1;
590 return massToInject(0, deltaT)/nParcelsToInject(0, deltaT);
594 template<
class CloudType>
595 template<
class TrackCloudType>
598 TrackCloudType&
cloud,
599 typename CloudType::parcelType::trackingData& td
602 const polyMesh& mesh = this->owner().mesh();
604 const scalar time = this->owner().
db().
time().
value();
609 label nParcelsAdded = 0;
610 scalar massAdded = 0;
627 const scalar t0 = timeStep0_ - SOI_, t1 = time - SOI_;
628 nParcels = nParcelsToInject(t0, t1);
629 mass = nParticleFixed_ < 0 ? massToInject(t0, t1) : NaN;
631 if (nParcels > 0 && (nParticleFixed_ > 0 || mass > 0))
637 else if (nParcels == 0 && (nParticleFixed_ < 0 && mass > 0))
657 const scalar deltaT =
673 const scalar padTime =
max(scalar(0), SOI_ - time0_);
677 forAll(parcelPtrs, parceli)
680 scalar timeInj = time0_ + padTime + deltaT*parceli/nParcels;
685 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
701 const scalar dt = timeInj - time0_;
720 constrainPosition(td,
p);
723 cloud.setParcelThermoProperties(
p);
726 setProperties(parceli, nParcels, timeInj, td,
p);
729 cloud.checkParcelProperties(
p, index());
741 p.stepFraction() = dt/td.trackTime();
745 p.nParticle() = nParticleFixed_;
751 if (nParticleFixed_ < 0)
753 setNumberOfParticles(parcelPtrs, mass);
757 forAll(parcelPtrs, parceli)
759 if (parcelPtrs.
set(parceli))
763 massAdded +=
p.nParticle()*
p.mass();
764 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
769 postInject(nParcelsAdded, massAdded, td);
773 template<
class CloudType>
774 template<
class TrackCloudType>
777 TrackCloudType&
cloud,
778 typename CloudType::parcelType::trackingData& td
781 const polyMesh& mesh = this->owner().mesh();
786 label nParcelsAdded = 0;
787 scalar massAdded = 0;
790 const label nParcels = nParcelsToInject(0, 1);
791 const scalar mass = nParticleFixed_ < 0 ? massToInject(0, 1) : NaN;
797 forAll(parcelPtrs, parceli)
802 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
834 constrainPosition(td,
p);
837 cloud.setParcelThermoProperties(
p);
840 setProperties(parceli, nParcels, 0, td,
p);
843 cloud.checkParcelProperties(
p, index());
849 p.stepFraction() = 0;
853 p.nParticle() = nParticleFixed_;
859 if (nParticleFixed_ < 0)
861 setNumberOfParticles(parcelPtrs, mass);
865 forAll(parcelPtrs, parceli)
867 if (parcelPtrs.
set(parceli))
871 massAdded +=
p.nParticle()*
p.mass();
872 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
877 postInject(nParcelsAdded, massAdded, td);
881 template<
class CloudType>
884 os <<
" " << this->modelName() <<
":" <<
nl
885 <<
" number of parcels added = " << parcelsAddedTotal_ <<
nl
886 <<
" mass introduced = " << massInjected_ <<
nl;
888 if (this->writeTime())
890 this->setModelProperty(
"massInjected", massInjected_);
891 this->setModelProperty(
"nInjections", nInjections_);
892 this->setModelProperty(
"parcelsAddedTotal", parcelsAddedTotal_);
893 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.
Run-time selectable general function of one variable.
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.
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.
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.
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.
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 unitConversion & 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...
A cloud is a collection of lagrangian particles.
A list of keyword definitions, which are a keyword followed by any number of values (e....
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
const Type & value() const
Return const reference to value.
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 & 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.
#define WarningInFunction
Report a warning using Foam::Warning.
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
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.
const dimensionSet dimless
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
const dimensionSet dimTime
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)
const dimensionSet dimMass
static const label labelMax
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.