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() || haveMassFlowRate)
131 this->owner().db().time().userUnits(),
137 const scalar massTotal =
dict.lookup<scalar>(
"massTotal",
dimMass);
139 if (!
dict.found(
"flowRateProfile"))
157 this->owner().db().time().userUnits(),
163 const scalar sumFlowRateProfile = flowRateProfile->integral(0, duration);
179 template<
class CloudType>
191 this->owner().db().time().userUnits(),
198 template<
class CloudType>
201 forAll(this->owner().injectors(), i)
203 if (this->owner().injectors()(i) ==
this)
213 template<
class CloudType>
226 auto findProcAndCell = [
this,&searchEngine](
const point&
pos)
232 label proci = celli >= 0 ? Pstream::myProcNo() : -1;
234 if (proci != Pstream::myProcNo())
247 celli = procAndCelli.
second();
253 pos += small*(this->owner().mesh().C()[celli] -
pos);
255 proci = procAndCelli.first();
256 celli = procAndCelli.second();
265 <<
"Cannot find parcel injection cell. "
274 if (proci == Pstream::myProcNo())
276 label nLocateBoundaryHits = 0;
277 particle p(searchEngine,
pos, celli, nLocateBoundaryHits);
279 if (nLocateBoundaryHits != 0)
282 <<
"Injection model " << this->
modelName()
283 <<
" for cloud " << this->owner().name()
284 <<
" did not accurately locate the position "
285 <<
pos <<
" within the mesh" <<
endl;
290 tetFacei =
p.tetFace();
298 template<
class CloudType>
301 typename CloudType::parcelType::trackingData& td,
305 const vector d = parcel.deviationFromMeshCentre(td.mesh);
307 if (d == vector::zero)
312 const label facei = parcel.face();
317 parcel.track(td.mesh, - d, 0);
326 td.mesh.cellCentres()[parcel.cell()] - parcel.position(td.mesh);
328 parcel.track(td.mesh, - d/2 + rootSmall*pc, 0);
329 parcel.track(td.mesh, - d/2 - rootSmall*pc, 0);
333 parcel.face() = facei;
337 template<
class CloudType>
340 switch (uniformParcelSize_)
342 case uniformParcelSize::nParticle:
344 case uniformParcelSize::surfaceArea:
346 case uniformParcelSize::volume:
354 template<
class CloudType>
363 switch (uniformParcelSize_)
365 case uniformParcelSize::nParticle:
367 case uniformParcelSize::surfaceArea:
369 case uniformParcelSize::volume:
376 scalar sumMassBySize = 0;
377 forAll(parcelPtrs, parceli)
379 if (parcelPtrs.
set(parceli))
382 sumMassBySize +=
p.mass()/size(
p);
389 forAll(parcelPtrs, parceli)
391 if (parcelPtrs.
set(parceli))
394 p.nParticle() = mass/size(
p)/sumMassBySize;
401 scalar massN = 0, minSizeN = vGreat, maxSizeN = -vGreat;
402 forAll(parcelPtrs, parceli)
404 if (parcelPtrs.
set(parceli))
407 massN +=
p.nParticle()*
p.mass();
408 minSizeN =
min(minSizeN,
p.nParticle()*size(
p));
409 maxSizeN =
max(minSizeN,
p.nParticle()*size(
p));
415 if (
mag(massN - mass) > rootSmall*(massN + mass)/2)
418 <<
"Parcels do not have the required mass"
425 if (maxSizeN - minSizeN > rootSmall*(maxSizeN + minSizeN)/2)
428 <<
"Parcel sizes are not uniform"
435 template<
class CloudType>
438 typename parcelType::trackingData& td
443 template<
class CloudType>
446 const label nParcelsAdded,
447 const scalar massAdded,
448 typename parcelType::trackingData& td
453 if (allNParcelsAdded > 0)
456 <<
"Cloud: " << this->owner().name()
458 <<
" Added " << allNParcelsAdded <<
" new parcels" <<
nl <<
endl;
462 nParcelsInjected_ += allNParcelsAdded;
471 template<
class CloudType>
476 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
479 this->template getModelProperty<scalar>(
"nParcelsInjected")
483 this->template getModelProperty<scalar>(
"massDeferred")
487 this->template getModelProperty<scalar>(
"nParcelsDeferred")
489 nParticleFixed_(-vGreat),
494 template<
class CloudType>
500 const word& modelType
505 massInjected_(this->template getModelProperty<scalar>(
"massInjected")),
508 this->template getModelProperty<scalar>(
"nParcelsInjected")
512 this->template getModelProperty<scalar>(
"massDeferred")
516 this->template getModelProperty<scalar>(
"nParcelsDeferred")
518 nParticleFixed_(
dict.lookupOrDefault<scalar>(
"nParticle", -vGreat)),
521 uniformParcelSizeNames_
523 !
dict.
found(
"parcelBasisType") && nParticleFixed_ > 0
529 :
dict.lookup<
word>(
"uniformParcelSize")
546 <<
"If nParticle is specified then the uniformParcelSize must be "
551 if (
owner.solution().transient())
558 template<
class CloudType>
566 massInjected_(im.massInjected_),
567 nParcelsInjected_(im.nParcelsInjected_),
568 massDeferred_(im.massDeferred_),
569 nParcelsDeferred_(im.nParcelsDeferred_),
570 nParticleFixed_(im.nParticleFixed_),
571 uniformParcelSize_(im.uniformParcelSize_)
577 template<
class CloudType>
584 template<
class CloudType>
589 template<
class CloudType>
592 const scalar deltaT =
593 this->owner().solution().transient() ? timeEnd() - timeStart() : 1;
595 return massToInject(0, deltaT)/nParcelsToInject(0, deltaT);
599 template<
class CloudType>
600 template<
class TrackCloudType>
603 TrackCloudType&
cloud,
604 typename CloudType::parcelType::trackingData& td
611 const scalar time1 = this->owner().db().time().value();
613 this->owner().db().time().value()
614 - this->owner().db().time().deltaTValue();
619 label nParcelsAdded = 0;
620 scalar massAdded = 0;
627 const scalar t0 = time0 - SOI_, t1 = time1 - SOI_;
631 const scalar nParcelsNoRound =
632 nParcelsToInject(t0, t1) + nParcelsDeferred_;
633 nParcels = floor(nParcelsNoRound);
634 nParcelsDeferred_ = nParcelsNoRound - nParcels;
637 if (nParticleFixed_ < 0)
641 mass = massToInject(t0, t1) + massDeferred_;
642 massDeferred_ = nParcels > 0 ? 0 : mass;
652 nParcelsDeferred_ = 0;
661 const scalar deltaT =
677 const scalar padTime =
max(scalar(0), SOI_ - time0);
681 forAll(parcelPtrs, parceli)
684 scalar timeInj = time0 + padTime + deltaT*parceli/nParcels;
689 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
706 const scalar dt = timeInj - time0;
725 constrainPosition(td,
p);
728 cloud.setParcelThermoProperties(
p);
731 setProperties(parceli, nParcels, timeInj, td,
p);
734 cloud.checkParcelProperties(
p, index());
746 p.stepFraction() = dt/td.trackTime();
750 p.nParticle() = nParticleFixed_;
756 if (nParticleFixed_ < 0)
758 setNumberOfParticles(parcelPtrs, mass);
762 forAll(parcelPtrs, parceli)
764 if (parcelPtrs.
set(parceli))
768 massAdded +=
p.nParticle()*
p.mass();
769 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
774 postInject(nParcelsAdded, massAdded, td);
778 template<
class CloudType>
779 template<
class TrackCloudType>
782 TrackCloudType&
cloud,
783 typename CloudType::parcelType::trackingData& td
793 label nParcelsAdded = 0;
794 scalar massAdded = 0;
797 const label nParcels = floor(nParcelsToInject(0, 1));
798 const scalar mass = nParticleFixed_ < 0 ? massToInject(0, 1) : NaN;
804 forAll(parcelPtrs, parceli)
809 label celli = -1, tetFacei = -1, tetPti = -1, facei = -1;
842 constrainPosition(td,
p);
845 cloud.setParcelThermoProperties(
p);
848 setProperties(parceli, nParcels, 0, td,
p);
851 cloud.checkParcelProperties(
p, index());
857 p.stepFraction() = 0;
861 p.nParticle() = nParticleFixed_;
867 if (nParticleFixed_ < 0)
869 setNumberOfParticles(parcelPtrs, mass);
873 forAll(parcelPtrs, parceli)
875 if (parcelPtrs.
set(parceli))
879 massAdded +=
p.nParticle()*
p.mass();
880 cloud.addParticle(parcelPtrs.
set(parceli,
nullptr).ptr());
885 postInject(nParcelsAdded, massAdded, td);
889 template<
class CloudType>
893 <<
" number of parcels added = " << nParcelsInjected_ <<
nl
894 <<
" mass introduced = " << massInjected_ <<
nl;
896 if (this->writeTime())
898 this->setModelProperty(
"massInjected", massInjected_);
899 this->setModelProperty(
"nParcelsInjected", nParcelsInjected_);
900 this->setModelProperty(
"massDeferred", massDeferred_);
901 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.
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.
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 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...
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.
const polyMesh & mesh() const
Return reference to polyMesh.
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.
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.
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
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.
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
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
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)
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.