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-2024 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 :
162  InjectionModel<CloudType>(dict, owner, modelName, typeName),
163  cellZoneName_(this->coeffDict().lookup("cellZone")),
164  massTotal_(this->readMassTotal(dict, owner)),
165  numberDensity_(this->coeffDict().template lookup<scalar>("numberDensity")),
166  injectorCoordinates_(),
167  injectorCells_(),
168  injectorTetFaces_(),
169  injectorTetPts_(),
170  diameters_(),
171  U0_(this->coeffDict().lookup("U0")),
172  sizeDistribution_
173  (
175  (
176  dimLength,
177  this->coeffDict().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 label parcelI,
313  const label nParcels,
314  const scalar time,
316  label& celli,
317  label& tetFacei,
318  label& tetPti,
319  label& facei
320 )
321 {
322  coordinates = injectorCoordinates_[parcelI];
323  celli = injectorCells_[parcelI];
324  tetFacei = injectorTetFaces_[parcelI];
325  tetPti = injectorTetPts_[parcelI];
326 }
327 
328 
329 template<class CloudType>
331 (
332  const label parcelI,
333  const label,
334  const scalar,
335  typename CloudType::parcelType::trackingData& td,
336  typename CloudType::parcelType& parcel
337 )
338 {
339  // set particle velocity
340  parcel.U() = U0_;
341 
342  // set particle diameter
343  parcel.d() = diameters_[parcelI];
344 }
345 
346 
347 template<class CloudType>
349 {
350  return false;
351 }
352 
353 
354 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
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 void setPositionAndCell(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.
virtual ~CellZoneInjection()
Destructor.
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:96
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
const polyMesh & mesh() const
Return reference to polyMesh.
Definition: fvMesh.H:443
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:449
A class for handling words, derived from string.
Definition: word.H:62
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.
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.
Definition: tracking.C:1259
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:258
barycentric barycentric01(randomGenerator &rndGen)
Generate a random barycentric coordinate within the unit tetrahedron.
Definition: barycentric.C:31
messageStream Info
const dimensionSet dimLength
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
static const char nl
Definition: Ostream.H:267
dictionary dict
randomGenerator rndGen(653213)