InjectedParticleInjection.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2015-2022 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
29 #include "mathematicalConstants.H"
30 #include "bitSet.H"
32 
33 using namespace Foam::constant;
34 
35 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
36 
37 template<class CloudType>
39 {
40  const injectedParticleCloud cloud(this->owner().mesh(), cloudName_);
41 
42  label nParticles = cloud.size();
43  List<scalar> time(nParticles);
44  List<vector> position(nParticles);
45  List<scalar> diameter(nParticles);
46  List<vector> U(nParticles);
47 
48  label particlei = 0;
49 
50  for (const injectedParticle& p : cloud)
51  {
52  time[particlei] = p.soi();
53  position[particlei] = p.position() + positionOffset_;
54  diameter[particlei] = p.d();
55  U[particlei] = p.U();
56 
57  ++particlei;
58  }
59 
60  // Combine all proc data
61  if (Pstream::parRun())
62  {
64  procTime[Pstream::myProcNo()].transfer(time);
65  Pstream::allGatherList(procTime);
66  time =
67  ListListOps::combine<List<scalar>>
68  (
69  procTime, accessOp<List<scalar>>()
70  );
71 
72  List<List<point>> procPosition(Pstream::nProcs());
73  procPosition[Pstream::myProcNo()].transfer(position);
74  Pstream::allGatherList(procPosition);
75  position =
76  ListListOps::combine<List<point>>
77  (
78  procPosition, accessOp<List<point>>()
79  );
80 
82  procD[Pstream::myProcNo()].transfer(diameter);
84  diameter =
85  ListListOps::combine<List<scalar>>
86  (
87  procD, accessOp<List<scalar>>()
88  );
89 
91  procU[Pstream::myProcNo()].transfer(U);
93  U =
94  ListListOps::combine<List<vector>>
95  (
96  procU, accessOp<List<vector>>()
97  );
98  }
99 
100  nParticles = time.size();
101 
102  // Reset SOI according to user selection
103  scalar minTime = min(time);
104  forAll(time, i)
105  {
106  time[i] -= minTime;
107  }
108 
109  // Sort and renumber to ensure lists in ascending time
110  labelList sortedIndices(Foam::sortedOrder(time));
111 
112  time_ = UIndirectList<scalar>(time, sortedIndices);
113  position_ = UIndirectList<point>(position, sortedIndices);
114  diameter_ = UIndirectList<scalar>(diameter, sortedIndices);
115  U_ = UIndirectList<vector>(U, sortedIndices);
116 
117  // Pre-calculate injected particle volumes
118  List<scalar> volume(nParticles);
119  scalar sumVolume = 0;
120  forAll(volume, i)
121  {
122  scalar vol = pow3(diameter_[i])*mathematical::pi/6.0;
123  volume[i] = vol;
124  sumVolume += vol;
125  }
126  volume_.transfer(volume);
127 
128  // Set the volume of particles to inject
129  this->volumeTotal_ = sumVolume;
130 
131  // Provide some feedback
132  Info<< " Read " << nParticles << " particles" << endl;
133 }
134 
135 
136 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
137 
138 template<class CloudType>
140 (
141  const dictionary& dict,
142  CloudType& owner,
143  const word& modelName
144 )
145 :
146  InjectionModel<CloudType>(dict, owner, modelName, typeName),
147  cloudName_(this->coeffDict().lookup("cloud")),
148  injectorCells_(),
149  injectorTetFaces_(),
150  injectorTetPts_(),
151  time_(this->template getModelProperty<scalarList>("time")),
152  position_(this->template getModelProperty<vectorList>("position")),
153  positionOffset_(this->coeffDict().lookup("positionOffset")),
154  diameter_(this->template getModelProperty<scalarList>("diameter")),
155  U_(this->template getModelProperty<vectorList>("U")),
156  volume_(this->template getModelProperty<scalarList>("volume")),
157  ignoreOutOfBounds_
158  (
159  this->coeffDict().getOrDefault("ignoreOutOfBounds", false)
160  ),
161  currentParticlei_
162  (
163  this->template getModelProperty<label>
164  (
165  "currentParticlei",
166  -1
167  )
168  )
169 {
171  {
173  << "Injector model: " << this->modelName()
174  << " Parcel basis must be set to fixed"
175  << exit(FatalError);
176  }
177 
178  if (!time_.size())
179  {
180  // Clean start
181  initialise();
182  }
183 
187 
188  updateMesh();
190  this->massTotal_ = this->volumeTotal_*this->owner().constProps().rho0();
191 }
192 
193 
194 template<class CloudType>
196 (
198 )
199 :
201  cloudName_(im.cloudName_),
202  injectorCells_(im.injectorCells_),
203  injectorTetFaces_(im.injectorTetFaces_),
204  injectorTetPts_(im.injectorTetPts_),
205  time_(im.time_),
206  position_(im.position_),
207  positionOffset_(im.positionOffset_),
208  diameter_(im.diameter_),
209  U_(im.U_),
210  volume_(im.volume_),
211  ignoreOutOfBounds_(im.ignoreOutOfBounds_),
212  currentParticlei_(im.currentParticlei_)
213 {}
214 
215 
216 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
217 
218 template<class CloudType>
220 {
221  label nRejected = 0;
222 
223  bitSet keep(position_.size(), true);
224 
225  forAll(position_, particlei)
226  {
227  if
228  (
229  !this->findCellAtPosition
230  (
231  injectorCells_[particlei],
232  injectorTetFaces_[particlei],
233  injectorTetPts_[particlei],
234  position_[particlei],
235  !ignoreOutOfBounds_
236  )
237  )
238  {
239  keep.unset(particlei);
240  nRejected++;
241  }
242  }
243 
244  if (nRejected > 0)
245  {
246  inplaceSubset(keep, time_);
247  inplaceSubset(keep, position_);
248  inplaceSubset(keep, diameter_);
249  inplaceSubset(keep, U_);
250  inplaceSubset(keep, volume_);
251  inplaceSubset(keep, injectorCells_);
252  inplaceSubset(keep, injectorTetFaces_);
253  inplaceSubset(keep, injectorTetPts_);
254 
255  Info<< " " << nRejected
256  << " particles ignored, out of bounds" << endl;
257  }
258 }
259 
260 
261 template<class CloudType>
263 {
264  return max(time_);
265 }
266 
267 
268 template<class CloudType>
270 (
271  const scalar time0,
272  const scalar time1
273 )
274 {
275  label nParticles = 0;
276  forAll(time_, particlei)
277  {
278  if ((time_[particlei] >= time0) && (time_[particlei] < time1))
279  {
280  ++nParticles;
281  }
282  }
284  return nParticles;
285 }
286 
287 
288 template<class CloudType>
290 (
291  const scalar time0,
292  const scalar time1
293 )
294 {
295  scalar sumVolume = 0;
296  forAll(time_, particlei)
297  {
298  if ((time_[particlei] >= time0) && (time_[particlei] < time1))
299  {
300  sumVolume += volume_[particlei];
301  }
302  }
304  return sumVolume;
305 }
306 
307 
308 template<class CloudType>
310 (
311  const label parceli,
312  const label nParcels,
313  const scalar time,
314  vector& position,
315  label& cellOwner,
316  label& tetFacei,
317  label& tetPti
318 )
319 {
320  // Note: optimisation - consume particle from lists to reduce storage
321  // as injection proceeds
322 
323  currentParticlei_++;
324 
325  position = position_[currentParticlei_];
326  cellOwner = injectorCells_[currentParticlei_];
327  tetFacei = injectorTetFaces_[currentParticlei_];
328  tetPti = injectorTetPts_[currentParticlei_];
329 }
330 
331 
332 template<class CloudType>
334 (
335  const label parceli,
336  const label,
337  const scalar,
338  typename CloudType::parcelType& parcel
339 )
340 {
341  // Set particle velocity
342  parcel.U() = U_[currentParticlei_];
344  // Set particle diameter
345  parcel.d() = diameter_[currentParticlei_];
346 }
347 
348 
349 template<class CloudType>
351 {
352  return false;
353 }
354 
355 
356 template<class CloudType>
358 (
359  const label
360 )
361 {
362  return true;
363 }
364 
365 
366 template<class CloudType>
368 {
370 
371  if (this->writeTime())
372  {
373  this->setModelProperty("currentParticlei", currentParticlei_);
374  this->setModelProperty("time", time_);
375  this->setModelProperty("position", position_);
376  this->setModelProperty("diameter", diameter_);
377  this->setModelProperty("U", U_);
378  this->setModelProperty("volume", volume_);
379  }
380 }
381 
382 
383 // ************************************************************************* //
Different types of constants.
virtual bool validInjection(const label parceli)
Return flag to identify whether or not injection of parcelI is.
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
virtual void setPositionAndCell(const label parceli, const label nParcels, const scalar time, vector &position, label &cellOwner, label &tetFacei, label &tetPti)
Set the injection position and owner cell, tetFace and tetPt.
scalar massTotal_
Total mass to inject [kg].
scalarList time_
List of injection time per particle [s].
labelList injectorTetFaces_
List of tetFace label per injector.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
InjectedParticleInjection(const dictionary &dict, CloudType &owner, const word &modelName)
Construct from dictionary.
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
Templated injection model class.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
Object access operator or list access operator (default is pass-through)
Definition: UList.H:1004
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
Primarily stores particle properties so that it can be injected at a later time. Note that this store...
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1074
Lookup type of boundary radiation properties.
Definition: lookup.H:57
void inplaceSubset(const BoolListType &select, ListType &input, const bool invert=false)
Inplace extract elements of the input list when select is true.
const word & modelName() const
Return const access to the name of the sub-model.
Definition: subModelBase.C:98
parcelBasis parcelBasis_
Parcel basis enumeration.
const CloudType & owner() const
Return const access to the owner cloud.
virtual label parcelsToInject(const scalar time0, const scalar time1)
Number of parcels to introduce relative to SOI.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
Replays an set of particle data based on an injectedParticleCloud, using the assumption of one partic...
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1065
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
A class for handling words, derived from Foam::string.
Definition: word.H:63
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:53
constexpr scalar pi(M_PI)
labelList injectorCells_
List of cell label per injector.
vectorList position_
List of position per particle [m].
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
virtual void info()
Write injection info.
ParcelType parcelType
Type of parcel the cloud was instantiated for.
Definition: DSMCCloud.H:290
const wordList volume
Standard volume field types (scalar, vector, tensor, etc)
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
scalar timeEnd() const
Return the end-of-injection time.
dimensionedScalar pow3(const dimensionedScalar &ds)
U
Definition: pEqn.H:72
labelList injectorTetPts_
List of tetPt label per injector.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:56
void initialise()
Initialise injectors.
virtual void setProperties(const label parceli, const label nParcels, const scalar time, typename CloudType::parcelType &parcel)
Set the parcel properties.
virtual void updateMesh()
Set injector locations when mesh is updated.
messageStream Info
Information stream (stdout output on master, null elsewhere)
scalar volumeTotal_
Total volume of particles introduced by this injector [m^3] Note: scaled to ensure massTotal is achie...
volScalarField & p
virtual scalar volumeToInject(const scalar time0, const scalar time1)
Volume of parcels to introduce relative to SOI.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:67
virtual bool fullyDescribed() const
Flag to identify whether model fully describes the parcel.
const List< typename ParcelType::constantProperties > & constProps() const
Return all of the constant properties.
Definition: DSMCCloudI.H:91