CellZoneInjection.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "CellZoneInjection.H"
27 #include "mathematicalConstants.H"
29 #include "globalIndex.H"
30 #include "Pstream.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 template<class CloudType>
36 (
37  const labelList& cellZoneCells
38 )
39 {
40  const fvMesh& mesh = this->owner().mesh();
41 
42  randomGenerator& rndGen = this->owner().rndGen();
43 
44  const label nCells = cellZoneCells.size();
45  DynamicList<barycentric> injectorCoordinates(nCells);
46  DynamicList<label> injectorCells(nCells);
47  DynamicList<label> injectorTetFaces(nCells);
48  DynamicList<label> injectorTetPts(nCells);
49 
50  scalar newParticlesTotal = 0;
51  label addParticlesTotal = 0;
52 
53  forAll(cellZoneCells, i)
54  {
55  const label celli = cellZoneCells[i];
56 
57  // Calc number of particles to add
58  const scalar newParticles = mesh.V()[celli]*numberDensity_;
59  newParticlesTotal += newParticles;
60  label addParticles = floor(newParticles);
61  addParticlesTotal += addParticles;
62 
63  const scalar diff = newParticlesTotal - addParticlesTotal;
64  if (diff > 1)
65  {
66  label corr = floor(diff);
67  addParticles += corr;
68  addParticlesTotal += corr;
69  }
70 
71  // Construct cell tet indices
72  const List<tetIndices> cellTetIs =
73  polyMeshTetDecomposition::cellTetIndices(mesh, celli);
74 
75  // Construct cell tet volume fractions
76  scalarField cTetVFrac(cellTetIs.size());
77  cTetVFrac[0] = cellTetIs[0].tet(mesh).mag();
78  for (label tetI = 1; tetI < cellTetIs.size(); tetI++)
79  {
80  cTetVFrac[tetI] =
81  cTetVFrac[tetI-1] + cellTetIs[tetI].tet(mesh).mag();
82  }
83  cTetVFrac /= cTetVFrac.last();
84 
85  // Set new particle position and cellId
86  for (label pI = 0; pI < addParticles; pI++)
87  {
88  const scalar volFrac = rndGen.sample01<scalar>();
89  label tetI = 0;
90  forAll(cTetVFrac, vfI)
91  {
92  if (cTetVFrac[vfI] > volFrac)
93  {
94  tetI = vfI;
95  break;
96  }
97  }
98 
99  injectorCoordinates.append(barycentric01(rndGen));
100  injectorCells.append(celli);
101  injectorTetFaces.append(cellTetIs[tetI].face());
102  injectorTetPts.append(cellTetIs[tetI].tetPt());
103  }
104  }
105 
106  // Accumulate into global lists. Set the coordinates and topology for local
107  // particles, and leave remote ones with invalid data.
108  globalIndex globalPositions(injectorCoordinates.size());
109 
110  List<barycentric> allInjectorCoordinates
111  (
112  globalPositions.size(),
113  barycentric::uniform(NaN)
114  );
115  List<label> allInjectorCells(globalPositions.size(), -1);
116  List<label> allInjectorTetFaces(globalPositions.size(), -1);
117  List<label> allInjectorTetPts(globalPositions.size(), -1);
118 
119  SubList<barycentric>
120  (
121  allInjectorCoordinates,
122  globalPositions.localSize(Pstream::myProcNo()),
123  globalPositions.offset(Pstream::myProcNo())
124  ) = injectorCoordinates;
125  SubList<label>
126  (
127  allInjectorCells,
128  globalPositions.localSize(Pstream::myProcNo()),
129  globalPositions.offset(Pstream::myProcNo())
130  ) = injectorCells;
131  SubList<label>
132  (
133  allInjectorTetFaces,
134  globalPositions.localSize(Pstream::myProcNo()),
135  globalPositions.offset(Pstream::myProcNo())
136  ) = injectorTetFaces;
137  SubList<label>
138  (
139  allInjectorTetPts,
140  globalPositions.localSize(Pstream::myProcNo()),
141  globalPositions.offset(Pstream::myProcNo())
142  ) = injectorTetPts;
143 
144  // Transfer data
145  injectorCoordinates_.transfer(allInjectorCoordinates);
146  injectorCells_.transfer(allInjectorCells);
147  injectorTetFaces_.transfer(allInjectorTetFaces);
148  injectorTetPts_.transfer(allInjectorTetPts);
149 }
150 
151 
152 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
153 
154 template<class CloudType>
156 (
157  const dictionary& dict,
158  CloudType& owner,
159  const word& modelName
160 )
161 :
163  cellZoneName_(this->typeDict().lookup("cellZone")),
164  massTotal_(this->readMassTotal(dict, owner)),
165  numberDensity_(this->typeDict().template lookup<scalar>("numberDensity")),
166  injectorCoordinates_(),
167  injectorCells_(),
168  injectorTetFaces_(),
169  injectorTetPts_(),
170  diameters_(),
171  U0_(this->typeDict().lookup("U0")),
172  sizeDistribution_
173  (
175  (
176  dimLength,
177  this->typeDict().subDict("sizeDistribution"),
178  this->sizeSampleQ(),
179  owner.rndGen().generator()
180  )
181  )
182 {
183  topoChange();
184 }
185 
186 
187 template<class CloudType>
189 (
191 )
192 :
194  cellZoneName_(im.cellZoneName_),
195  massTotal_(im.massTotal_),
196  numberDensity_(im.numberDensity_),
197  injectorCoordinates_(im.injectorCoordinates_),
198  injectorCells_(im.injectorCells_),
199  injectorTetFaces_(im.injectorTetFaces_),
200  injectorTetPts_(im.injectorTetPts_),
201  diameters_(im.diameters_),
202  U0_(im.U0_),
203  sizeDistribution_(im.sizeDistribution_, false)
204 {}
205 
206 
207 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
208 
209 template<class CloudType>
211 {}
212 
213 
214 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
215 
216 template<class CloudType>
218 {
219  // Set/cache the injector cells
220  const fvMesh& mesh = this->owner().mesh();
221  const label zoneI = mesh.cellZones().findIndex(cellZoneName_);
222 
223  if (zoneI < 0)
224  {
226  << "Unknown cell zone name: " << cellZoneName_
227  << ". Valid cell zones are: " << mesh.cellZones().toc()
228  << nl << exit(FatalError);
229  }
230 
231  const labelList& cellZoneCells = mesh.cellZones()[zoneI];
232  const label nCells = cellZoneCells.size();
233  const scalar nCellsTotal = returnReduce(nCells, sumOp<label>());
234  const scalar VCells = sum(scalarField(mesh.V(), cellZoneCells));
235  const scalar VCellsTotal = returnReduce(VCells, sumOp<scalar>());
236  Info<< " cell zone size = " << nCellsTotal << endl;
237  Info<< " cell zone volume = " << VCellsTotal << endl;
238 
239  if ((nCellsTotal == 0) || (VCellsTotal*numberDensity_ < 1))
240  {
242  << "Number of particles to be added to cellZone " << cellZoneName_
243  << " is zero" << endl;
244  }
245  else
246  {
247  setPositions(cellZoneCells);
248 
249  Info<< " number density = " << numberDensity_ << nl
250  << " number of particles = " << injectorCoordinates_.size()
251  << endl;
252 
253  // Construct parcel diameters
254  diameters_.setSize(injectorCoordinates_.size());
255  forAll(diameters_, i)
256  {
257  diameters_[i] = sizeDistribution_->sample();
258  }
259  }
260 }
261 
262 
263 template<class CloudType>
265 {
266  // Not used
267  return this->SOI_;
268 }
269 
270 
271 template<class CloudType>
273 (
274  const scalar t0,
275  const scalar t1
276 )
277 {
278  // All parcels introduced at SOI
279  if (0 >= t0 && 0 < t1)
280  {
281  return injectorCoordinates_.size();
282  }
283  else
284  {
285  return 0;
286  }
287 }
288 
289 
290 template<class CloudType>
292 (
293  const scalar t0,
294  const scalar t1
295 )
296 {
297  // All parcels introduced at SOI
298  if (0 >= t0 && 0 < t1)
299  {
300  return massTotal_;
301  }
302  else
303  {
304  return 0;
305  }
306 }
307 
308 
309 template<class CloudType>
311 (
312  const meshSearch& searchEngine,
313  const label parcelI,
314  const label nParcels,
315  const scalar time,
317  label& celli,
318  label& tetFacei,
319  label& tetPti,
320  label& facei
321 )
322 {
323  coordinates = injectorCoordinates_[parcelI];
324  celli = injectorCells_[parcelI];
325  tetFacei = injectorTetFaces_[parcelI];
326  tetPti = injectorTetPts_[parcelI];
327 }
328 
329 
330 template<class CloudType>
332 (
333  const label parcelI,
334  const label,
335  const scalar,
336  typename CloudType::parcelType::trackingData& td,
337  typename CloudType::parcelType& parcel
338 )
339 {
340  // set particle velocity
341  parcel.U() = U0_;
342 
343  // set particle diameter
344  parcel.d() = diameters_[parcelI];
345 }
346 
347 
348 template<class CloudType>
350 {
351  return false;
352 }
353 
354 
355 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Injection positions specified by a particle number density within a cell set.
virtual scalar nParcelsToInject(const scalar time0, const scalar time1)
Number of parcels to introduce relative to SOI.
virtual void topoChange()
Set injector locations when mesh is updated.
virtual void setProperties(const label parcelI, const label nParcels, const scalar time, typename CloudType::parcelType::trackingData &td, typename CloudType::parcelType &parcel)
Set the parcel properties.
virtual ~CellZoneInjection()
Destructor.
virtual void setPositionAndCell(const meshSearch &searchEngine, const label parcelI, const label nParcels, const scalar time, barycentric &coordinates, label &celli, label &tetFacei, label &tetPti, label &facei)
Set the injection position and owner cell, tetFace and tetPt.
CellZoneInjection(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
virtual bool fullyDescribed() const
Flag to identify whether model fully describes the parcel.
virtual scalar timeEnd() const
Return the end-of-injection time.
virtual scalar massToInject(const scalar time0, const scalar time1)
Parcel mass to introduce relative to SOI.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:80
ParcelType parcelType
Type of parcel the cloud was instantiated for.
Definition: DSMCCloud.H:225
wordList toc() const
Return the table of contents.
Templated injection model class.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
label findIndex(const word &key) const
Return the index of the given the key or -1 if not found.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Base class for statistical distributions.
Definition: distribution.H:76
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const DimensionedField< scalar, fvMesh > & V() const
Return cell volumes.
Mesh object that implements searches within the local cells and faces.
Definition: meshSearch.H:59
Motion of the mesh specified as a list of pointMeshMovers.
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:438
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.
Definition: word.H:63
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
volScalarField scalarField(fieldObject, mesh)
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionSet time
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.
Definition: tracking.C:1258
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
const dimensionSet & dimLength
Definition: dimensions.C:141
barycentric barycentric01(randomGenerator &rndGen)
Generate a random barycentric coordinate within the unit tetrahedron.
Definition: barycentric.C:31
messageStream Info
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:409
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
error FatalError
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
static const char nl
Definition: Ostream.H:297
dictionary dict
randomGenerator rndGen(653213)