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 time0,
275  const scalar time1
276 )
277 {
278  // All parcels introduced at SOI
279  if (0 >= time0 && 0 < time1)
280  {
281  return injectorCoordinates_.size();
282  }
283  else
284  {
285  return 0;
286  }
287 }
288 
289 
290 template<class CloudType>
292 (
293  const scalar time0,
294  const scalar time1
295 )
296 {
297  // All parcels introduced at SOI
298  if (0 >= time0 && 0 < time1)
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,
315  barycentric& coordinates,
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:434
Injection positions specified by a particle number density within a cell set.
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.
virtual label nParcelsToInject(const scalar time0, const scalar time1)
Number of parcels to introduce relative to SOI.
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 keyword definitions, which are a keyword followed by any number of values (e....
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:99
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
const polyMesh & mesh() const
Return reference to polyMesh.
Definition: fvMesh.H:441
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:452
A class for handling words, derived from string.
Definition: word.H:62
#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)
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:257
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
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
error FatalError
static const char nl
Definition: Ostream.H:266
dictionary dict
randomGenerator rndGen(653213)