LocalInteraction.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 "LocalInteraction.H"
27 #include "wordAndDictionary.H"
28 
29 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
30 
31 namespace Foam
32 {
33 
35 :
36  public Tuple2<wordRe, dictionary>
37 {
39 
41 
43 };
44 
45 
47 {
48  wd.first() = wordRe(is);
49  dictionary d(is);
50  wd.second().transfer(d);
51  return is;
52 }
53 
54 
56 {
57  return os << wd.first() << token::SPACE << wd.second();
58 }
59 
60 
62 {}
63 
64 
66 {
67  is >> *this;
68 }
69 
70 }
71 
72 
73 // * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
74 
75 template<class CloudType>
77 (
78  const dictionary& dict,
80 )
81 :
83  patchInteractionTypes_
84  (
85  this->owner().mesh().poly().boundary().size(),
87  ),
88  patchEs_(this->owner().mesh().poly().boundary().size(), NaN),
89  patchMus_(this->owner().mesh().poly().boundary().size(), NaN),
90  nEscape_(this->owner().mesh().poly().boundary().size(), 0),
91  massEscape_(this->owner().mesh().poly().boundary().size(), scalar(0)),
92  nStick_(this->owner().mesh().poly().boundary().size(), 0),
93  massStick_(this->owner().mesh().poly().boundary().size(), scalar(0)),
94  writeFields_(this->typeDict().lookupOrDefault("writeFields", false)),
95  massEscapePtr_(nullptr),
96  massStickPtr_(nullptr)
97 {
98  const polyBoundaryMesh& patches = this->owner().mesh().poly().boundary();
99 
100  if (writeFields_)
101  {
102  const word massEscapeName(this->owner().name() + ":massEscape");
103  const word massStickName(this->owner().name() + ":massStick");
104 
105  Info<< " Interaction fields will be written to " << massEscapeName
106  << " and " << massStickName << endl;
107 
108  (void)massEscape();
109  (void)massStick();
110 }
111  else
112  {
113  Info<< " Interaction fields will not be written" << endl;
114  }
115 
116  // Get the patch-settings dictionaries
117  dictionary patchesDict;
118  if (this->typeDict().isDict("patches"))
119  {
120  patchesDict = this->typeDict().subDict("patches");
121  }
122  else
123  {
124  const List<wordReAndDictionary> patchNameAndDicts
125  (
126  this->typeDict().lookup("patches")
127  );
128 
129  forAll(patchNameAndDicts, dicti)
130  {
131  patchesDict.set
132  (
133  keyType(string(patchNameAndDicts[dicti].first())),
134  patchNameAndDicts[dicti].second()
135  );
136  }
137  }
138 
139  // Read the patch settings
140  wordList unspecifiedNonConstraintPatches;
142  {
143  const word& patchName = patches[patchi].name();
144 
145  const bool havePatchDict = patchesDict.found(patchName);
146 
147  const bool patchIsConstraint = patches[patchi].constraint();
148 
149  // No settings for constrained patch. No model.
150  if (!havePatchDict && patchIsConstraint)
151  {
152  patchInteractionTypes_[patchi] =
154  continue;
155  }
156 
157  // No settings for non-constrained patch. Error.
158  if (!havePatchDict && !patchIsConstraint)
159  {
160  unspecifiedNonConstraintPatches.append(patches[patchi].name());
161  continue;
162  }
163 
164  const dictionary& patchDict = patchesDict.subDict(patchName);
165 
166  // Settings for constrained patch. Ignored unless "patchType" is
167  // correctly specified.
168  if (havePatchDict && patchIsConstraint)
169  {
170  if (!patchDict.found("patchType"))
171  {
172  patchInteractionTypes_[patchi] =
174  continue;
175  }
176 
177  const word patchType = patchDict.lookup<word>("patchType");
178 
179  if (patchType != patches[patchi].type())
180  {
182  << "Type " << patchType
183  << " specified for patch " << patchName
184  << " does not match the patch type "
185  << patches[patchi].type() << exit(FatalError);
186  }
187  }
188 
189  // Read and set the interaction model
190  const word itName = patchDict.lookup<word>("type");
191  const interactionType it = this->wordToInteractionType(itName);
192 
194  {
196  << "Unknown patch interaction type "
197  << itName << " for patch " << patchName
198  << ". Valid types are:"
200  << nl << exit(FatalError);
201  }
202 
203  patchInteractionTypes_[patchi] = it;
204 
206  {
207  patchEs_[patchi] = patchDict.lookupOrDefault<scalar>("e", 1);
208  patchMus_[patchi] = patchDict.lookupOrDefault<scalar>("mu", 0);
209  }
210  }
211 
212  // Error if interactions are unspecified for non-constraint patches
213  if (!unspecifiedNonConstraintPatches.empty())
214  {
216  << "No interaction type was specified for non-constraint patches: "
217  << unspecifiedNonConstraintPatches
218  << exit(FatalError);
219  }
220 }
221 
222 
223 template<class CloudType>
225 (
226  const LocalInteraction<CloudType>& pim
227 )
228 :
230  patchInteractionTypes_(pim.patchInteractionTypes_),
231  patchEs_(pim.patchEs_),
232  patchMus_(pim.patchMus_),
233  nEscape_(pim.nEscape_),
234  massEscape_(pim.massEscape_),
235  nStick_(pim.nStick_),
236  massStick_(pim.massStick_),
237  writeFields_(pim.writeFields_),
238  massEscapePtr_(nullptr),
239  massStickPtr_(nullptr)
240 {}
241 
242 
243 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
244 
245 template<class CloudType>
247 {}
248 
249 
250 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
251 
252 template<class CloudType>
254 {
255  if (!massEscapePtr_.valid())
256  {
257  const fvMesh& mesh = this->owner().mesh();
258 
259  massEscapePtr_.reset
260  (
261  new volScalarField
262  (
263  IOobject
264  (
265  this->owner().name() + ":massEscape",
266  mesh.time().name(),
267  mesh,
270  ),
271  mesh,
273  )
274  );
275  }
276 
277  return massEscapePtr_();
278 }
279 
280 
281 template<class CloudType>
283 {
284  if (!massStickPtr_.valid())
285  {
286  const fvMesh& mesh = this->owner().mesh();
287 
288  massStickPtr_.reset
289  (
290  new volScalarField
291  (
292  IOobject
293  (
294  this->owner().name() + ":massStick",
295  mesh.time().name(),
296  mesh,
299  ),
300  mesh,
302  )
303  );
304  }
305 
306  return massStickPtr_();
307 }
308 
309 
310 template<class CloudType>
312 (
313  typename CloudType::parcelType& p,
314  const polyPatch& pp,
315  bool& keepParticle
316 )
317 {
318  const label patchi = pp.index();
319 
320  if (isA<processorPolyPatch>(pp))
321  {
322  return false;
323  }
324 
325  switch (patchInteractionTypes_[patchi])
326  {
328  {
329  return false;
330  }
331 
333  {
334  const scalar dm = p.mass()*p.nParticle();
335 
336  keepParticle = false;
337  p.moving() = false;
338  p.U() = Zero;
339  nEscape_[patchi] ++;
340  massEscape_[patchi] += dm;
341 
342  if (writeFields_)
343  {
344  const label patchFacei = pp.whichFace(p.face());
345  massEscape().boundaryFieldRef()[patchi][patchFacei] += dm;
346  }
347 
348  return true;
349  }
350 
352  {
353  const scalar dm = p.mass()*p.nParticle();
354 
355  keepParticle = true;
356  p.moving() = false;
357  p.U() = Zero;
358  nStick_[patchi] ++;
359  massStick_[patchi] += dm;
360 
361  if (writeFields_)
362  {
363  const label patchFacei = pp.whichFace(p.face());
364  massStick().boundaryFieldRef()[patchi][patchFacei] += dm;
365  }
366 
367  return true;
368  }
369 
371  {
372  keepParticle = true;
373  p.moving() = true;
374 
375  vector nw, Up;
376  this->owner().patchData(p, pp, nw, Up);
377 
378  // Make motion relative to patch velocity
379  p.U() -= Up;
380 
381  const scalar Un = p.U() & nw;
382  const vector Ut = p.U() - Un*nw;
383 
384  if (Un > 0)
385  {
386  p.U() -= (1 + patchEs_[patchi])*Un*nw;
387  }
388 
389  p.U() -= patchMus_[patchi]*Ut;
390 
391  // Return velocity to global space
392  p.U() += Up;
393 
394  return true;
395  }
396 
397  default:
398  {
399  return false;
400  }
401  }
402 
403  return false;
404 }
405 
406 
407 template<class CloudType>
409 {
410  const polyBoundaryMesh& patches = this->owner().mesh().poly().boundary();
411 
412  // Determine the number of non-processor patches
414  for (; isA<processorPolyPatch>(patches[nPatches - 1]); nPatches --);
415 
416  // Retrieve any stored data
417  labelList npe0(nPatches, 0);
418  this->getModelProperty("nEscape", npe0);
419 
420  scalarList mpe0(nPatches, scalar(0));
421  this->getModelProperty("massEscape", mpe0);
422 
423  labelList nps0(nPatches, 0);
424  this->getModelProperty("nStick", nps0);
425 
426  scalarList mps0(nPatches, scalar(0));
427  this->getModelProperty("massStick", mps0);
428 
429  // Accumulate current data
430  labelList npe(SubList<label>(nEscape_, nPatches));
432  SubField<label>(npe) += npe0;
433 
434  scalarList mpe(SubList<scalar>(massEscape_, nPatches));
436  SubField<scalar>(mpe) += mpe0;
437 
438  labelList nps(SubList<label>(nStick_, nPatches));
440  SubField<label>(nps) += nps0;
441 
442  scalarList mps(SubList<scalar>(massStick_, nPatches));
444  SubField<scalar>(mps) += mps0;
445 
446  for (label patchi = 0; patchi < nPatches; ++ patchi)
447  {
448  if
449  (
450  patchInteractionTypes_[patchi]
452  )
453  {
454  os << " Parcel fate (number, mass) : patch "
455  << this->owner().mesh().poly().boundary()[patchi].name() << nl
456  << " - escape = " << npe[patchi]
457  << ", " << mpe[patchi] << nl
458  << " - stick = " << nps[patchi]
459  << ", " << mps[patchi] << nl;
460  }
461  }
462 
463  if (this->writeTime())
464  {
465  this->setModelProperty("nEscape", npe);
466  nEscape_ = 0;
467 
468  this->setModelProperty("massEscape", mpe);
469  massEscape_ = scalar(0);
470 
471  this->setModelProperty("nStick", nps);
472  nStick_ = 0;
473 
474  this->setModelProperty("massStick", mps);
475  massStick_ = scalar(0);
476  }
477 }
478 
479 
480 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
const CloudType & owner() const
Return const access to the owner cloud.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:80
ParcelType parcelType
Type of parcel the cloud was instantiated for.
Definition: DSMCCloud.H:225
const fvMesh & mesh() const
Return references to the mesh.
Definition: DSMCCloudI.H:41
Generic GeometricField class.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
virtual const fileName & name() const
Return the name of the stream.
Definition: IOstream.H:297
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:60
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
Patch interaction specified on a patch-by-patch basis.
virtual void info(Ostream &os)
Write patch interaction info to stream.
LocalInteraction(const dictionary &dict, CloudType &owner)
Construct from dictionary.
volScalarField & massStick()
Return access to the massStick field.
volScalarField & massEscape()
Return access to the massEscape field.
virtual ~LocalInteraction()
Destructor.
virtual bool correct(typename CloudType::parcelType &p, const polyPatch &pp, bool &keepParticle)
Apply velocity correction.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
Templated patch interaction model class.
static interactionType wordToInteractionType(const word &itWord)
Convert word to interaction result.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
Pre-declare related SubField type.
Definition: SubField.H:63
A List obtained as a section of another List.
Definition: SubList.H:56
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
const Type1 & first() const
Return first.
Definition: Tuple2.H:119
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
Base class for clouds. Provides a basic evolution algorithm, models, and a database for caching deriv...
Definition: cloud.H:61
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
void transfer(dictionary &)
Transfer the contents of the argument and annul the argument.
Definition: dictionary.C:1367
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
bool isDict(const word &) const
Check if entry is a sub-dictionary.
Definition: dictionary.C:732
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:778
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:468
const word & name() const
Return const reference to name.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
A class for handling keywords in dictionaries.
Definition: keyType.H:69
label index() const
Return the index of this patch in the boundaryMesh.
Foam::polyBoundaryMesh.
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:360
void reset(const label nPoints, const label nInternalFaces, const label nFaces, const label nCells)
Reset this primitiveMesh given the primitive array sizes.
const dictionary & typeDict() const
Return const access to the coefficients dictionary.
Definition: subModelBase.C:127
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A wordRe is a word, but can also have a regular expression for matching words.
Definition: wordRe.H:77
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
label patchi
const fvPatchList & patches
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
Istream & operator>>(Istream &, pointEdgeDist &)
Definition: pointEdgeDist.C:41
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
const dimensionSet & dimMass
Definition: dimensions.C:140
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
messageStream Info
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
Ostream & operator<<(Ostream &os, const fvConstraints &constraints)
error FatalError
static const char nl
Definition: Ostream.H:297
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
faceListList boundary(nPatches)
label nPatches
Definition: readKivaGrid.H:396
dictionary dict
volScalarField & p