genericPatchFieldBase.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) 2021 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 
28 #include "genericPatchFieldBase.H"
29 #include "messageStream.H"
30 
31 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32 
33 bool Foam::genericPatchFieldBase::checkFieldSize
34 (
35  const label fieldSize,
36  const label patchSize,
37  const word& patchName,
38  const keyType& key,
39  const IOobject& io
40 ) const
41 {
42  const bool ok = (fieldSize == patchSize);
43 
44  if (!ok)
45  {
47  << "\n size of field " << key
48  << " (" << fieldSize << ") != patch size (" << patchSize << ')'
49  << "\n on patch " << patchName
50  << " of field " << io.name() << " in file "
51  << io.objectPath() << nl
52  << exit(FatalIOError);
53  }
54 
55  return ok;
56 }
57 
58 
59 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
60 
62 (
63  const dictionary& dict
64 )
65 :
66  actualTypeName_(dict.get<word>("type")),
67  dict_(dict)
68 {}
69 
70 
72 (
73  const Foam::zero,
74  const genericPatchFieldBase& rhs
75 )
76 :
77  actualTypeName_(rhs.actualTypeName_),
78  dict_(rhs.dict_)
79 {}
80 
81 
82 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
83 
85 (
86  const word& patchName,
87  const IOobject& io
88 ) const
89 {
91  << " (actual type " << actualTypeName_ << ')'
92  << "\n on patch " << patchName
93  << " of field " << io.name() << " in file " << io.objectPath() << nl
94  << nl
95  << " You are probably trying to solve for a field with a "
96  "generic boundary condition." << nl;
97 }
98 
99 
101 (
102  const word& entryName,
103  const word& patchName,
104  const IOobject& io
105 ) const
106 {
108  << nl
109  << " Missing required '" << entryName << "' entry"
110  << " on patch " << patchName
111  << " of field " << io.name() << " in file " << io.objectPath() << nl
112  << " (Actual type " << actualTypeName_ << ')' << nl << nl
113  << " Please add the '" << entryName << "' entry to the"
114  " write function of the user-defined boundary-condition" << nl
115  << exit(FatalIOError);
116 }
117 
118 
120 (
121  const label patchSize,
122  const word& patchName,
123  const IOobject& io,
124  const bool separateValue
125 )
126 {
127  for (const entry& dEntry : dict_)
128  {
129  const keyType& key = dEntry.keyword();
130 
131  if (key == "type" || (separateValue && key == "value"))
132  {
133  // "type" and possibly "value" handled differently
134  }
135  else
136  {
137  processEntry(dEntry, patchSize, patchName, io);
138  }
139  }
140 }
141 
142 
144 (
145  const entry& dEntry,
146  const label patchSize,
147  const word& patchName,
148  const IOobject& io
149 )
150 {
151  if (!dEntry.isStream())
152  {
153  return false;
154  }
155 
156  const keyType& key = dEntry.keyword();
157  ITstream& is = dEntry.stream();
158 
159  if (is.empty())
160  {
161  return false;
162  }
163 
164  #undef FIELDSIZE_CHECK
165  #define FIELDSIZE_CHECK(fieldLen) \
166  checkFieldSize(fieldLen, patchSize, patchName, key, io)
167 
168 
169  // First token
170  token tok(is);
171 
172  if (tok.isWord("nonuniform"))
173  {
174  is >> tok;
175 
176  if (tok.isLabel(0))
177  {
178  // For v2006 and earlier, could have a plain untyped 0
179  // without a compound type.
180  // Just treat as scalar and hope for the best.
181  scalarFields_.insert(key, autoPtr<scalarField>::New());
182  }
183  else if (!tok.isCompound())
184  {
186  << "\n non-compound token following 'nonuniform'"
187  << "\n on patch " << patchName << " field "
188  << io.name() << " in file "
189  << io.objectPath() << nl
190  << exit(FatalIOError);
191  return false;
192  }
193  else if
194  (
195  tok.compoundToken().type()
196  == token::Compound<List<scalar>>::typeName
197  )
198  {
199  auto fPtr = autoPtr<scalarField>::New();
200 
201  fPtr->transfer
202  (
203  dynamicCast<token::Compound<List<scalar>>>
204  (
205  tok.transferCompoundToken(is)
206  )
207  );
208 
209  if (!FIELDSIZE_CHECK(fPtr->size()))
210  {
211  return false;
212  }
213 
214  scalarFields_.insert(key, fPtr);
215  }
216  else if
217  (
218  tok.compoundToken().type()
219  == token::Compound<List<vector>>::typeName
220  )
221  {
222  auto fPtr = autoPtr<vectorField>::New();
223 
224  fPtr->transfer
225  (
226  dynamicCast<token::Compound<List<vector>>>
227  (
228  tok.transferCompoundToken(is)
229  )
230  );
231 
232  if (!FIELDSIZE_CHECK(fPtr->size()))
233  {
234  return false;
235  }
236  vectorFields_.insert(key, fPtr);
237  }
238  else if
239  (
240  tok.compoundToken().type()
241  == token::Compound<List<sphericalTensor>>::typeName
242  )
243  {
245 
246  fPtr->transfer
247  (
248  dynamicCast<token::Compound<List<sphericalTensor>>>
249  (
250  tok.transferCompoundToken(is)
251  )
252  );
253 
254  if (!FIELDSIZE_CHECK(fPtr->size()))
255  {
256  return false;
257  }
258 
259  sphTensorFields_.insert(key, fPtr);
260  }
261  else if
262  (
263  tok.compoundToken().type()
264  == token::Compound<List<symmTensor>>::typeName
265  )
266  {
267  auto fPtr = autoPtr<symmTensorField>::New();
268 
269  fPtr->transfer
270  (
271  dynamicCast<token::Compound<List<symmTensor>>>
272  (
273  tok.transferCompoundToken(is)
274  )
275  );
276 
277  if (!FIELDSIZE_CHECK(fPtr->size()))
278  {
279  return false;
280  }
281 
282  symmTensorFields_.insert(key, fPtr);
283  }
284  else if
285  (
286  tok.compoundToken().type()
287  == token::Compound<List<tensor>>::typeName
288  )
289  {
290  auto fPtr = autoPtr<tensorField>::New();
291 
292  fPtr->transfer
293  (
294  dynamicCast<token::Compound<List<tensor>>>
295  (
296  tok.transferCompoundToken(is)
297  )
298  );
299 
300  if (!FIELDSIZE_CHECK(fPtr->size()))
301  {
302  return false;
303  }
304 
305  tensorFields_.insert(key, fPtr);
306  }
307  else
308  {
310  << "\n unsupported compound " << tok.compoundToken()
311  << "\n on patch " << patchName << " of field "
312  << io.name() << " in file "
313  << io.objectPath() << nl
314  << exit(FatalIOError);
315  return false;
316  }
317  }
318  else if (tok.isWord("uniform"))
319  {
320  is >> tok;
321 
322  if (!tok.isPunctuation())
323  {
324  scalarFields_.insert
325  (
326  key,
327  autoPtr<scalarField>::New(patchSize, tok.number())
328  );
329  }
330  else
331  {
332  // Read vector-space as list of scalars
333  is.putBack(tok);
334 
335  scalarList list(is);
336 
337  if (list.size() == vector::nComponents)
338  {
339  vector vs(list[0], list[1], list[2]);
340 
341  vectorFields_.insert
342  (
343  key,
345  (
346  patchSize,
347  vs
348  )
349  );
350  }
351  else if (list.size() == sphericalTensor::nComponents)
352  {
353  sphericalTensor vs(list[0]);
354 
355  sphTensorFields_.insert
356  (
357  key,
359  (
360  patchSize,
361  vs
362  )
363  );
364  }
365  else if (list.size() == symmTensor::nComponents)
366  {
367  symmTensor vs
368  (
369  list[0], list[1], list[2],
370  list[3], list[4],
371  list[5]
372  );
373 
374  symmTensorFields_.insert
375  (
376  key,
378  (
379  patchSize,
380  vs
381  )
382  );
383  }
384  else if (list.size() == tensor::nComponents)
385  {
386  tensor vs
387  (
388  list[0], list[1], list[2],
389  list[3], list[4], list[5],
390  list[6], list[7], list[8]
391  );
392 
393  tensorFields_.insert
394  (
395  key,
397  (
398  patchSize,
399  vs
400  )
401  );
402  }
403  else
404  {
406  << "\n unrecognised native type " << flatOutput(list)
407  << "\n on patch " << patchName << " of field "
408  << io.name() << " in file "
409  << io.objectPath() << nl
410  << exit(FatalIOError);
411  return false;
412  }
413  }
414  }
415 
416  #undef FIELDSIZE_CHECK
417 
418  return true;
419 }
420 
421 
423 (
424  const entry& e,
425  Ostream& os
426 ) const
427 {
428  const keyType& key = e.keyword();
429 
430  if
431  (
432  e.isStream()
433  && e.stream().size()
434  && e.stream()[0].isWord("nonuniform")
435  )
436  {
437  if (scalarFields_.found(key))
438  {
439  scalarFields_.cfind(key)()->writeEntry(key, os);
440  }
441  else if (vectorFields_.found(key))
442  {
443  vectorFields_.cfind(key)()->writeEntry(key, os);
444  }
445  else if (sphTensorFields_.found(key))
446  {
447  sphTensorFields_.cfind(key)()->writeEntry(key, os);
448  }
449  else if (symmTensorFields_.found(key))
450  {
451  symmTensorFields_.cfind(key)()->writeEntry(key, os);
452  }
453  else if (tensorFields_.found(key))
454  {
455  tensorFields_.cfind(key)()->writeEntry(key, os);
456  }
457  }
458  else
459  {
460  e.write(os);
461  }
462 }
463 
464 
466 (
467  Ostream& os,
468  const bool separateValue
469 ) const
470 {
471  os.writeEntry("type", actualTypeName_);
472 
473  for (const entry& dEntry : dict_)
474  {
475  const keyType& key = dEntry.keyword();
476 
477  if (key == "type" || (separateValue && key == "value"))
478  {
479  // NB: "type" written first, "value" possibly separately
480  }
481  else
482  {
483  putEntry(dEntry, os);
484  }
485  }
486 }
487 
488 
490 (
491  const genericPatchFieldBase& rhs,
492  const labelList& addr
493 )
494 {
495  forAllIters(scalarFields_, iter)
496  {
497  const auto iter2 = rhs.scalarFields_.cfind(iter.key());
498 
499  if (iter2.found())
500  {
501  (*iter)->rmap(*iter2(), addr);
502  }
503  }
504 
505  forAllIters(vectorFields_, iter)
506  {
507  const auto iter2 = rhs.vectorFields_.cfind(iter.key());
508 
509  if (iter2.found())
510  {
511  (*iter)->rmap(*iter2(), addr);
512  }
513  }
514 
515  forAllIters(sphTensorFields_, iter)
516  {
517  const auto iter2 = rhs.sphTensorFields_.cfind(iter.key());
518 
519  if (iter2.found())
520  {
521  (*iter)->rmap(*iter2(), addr);
522  }
523  }
524 
525  forAllIters(symmTensorFields_, iter)
526  {
527  const auto iter2 = rhs.symmTensorFields_.cfind(iter.key());
528 
529  if (iter2.found())
530  {
531  (*iter)->rmap(*iter2(), addr);
532  }
533  }
534 
535  forAllIters(tensorFields_, iter)
536  {
537  const auto iter2 = rhs.tensorFields_.find(iter.key());
538 
539  if (iter2.found())
540  {
541  (*iter)->rmap(*iter2(), addr);
542  }
543  }
544 }
545 
546 
547 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
A class for handling keywords in dictionaries.
Definition: keyType.H:66
dictionary dict
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
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:120
void writeGeneric(Ostream &os, const bool separateValue) const
Write all generic entries from dictionary, optionally treating the "value" entry separately.
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:150
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Tensor< scalar > tensor
Definition: symmTensor.H:57
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:312
bool processEntry(const entry &dEntry, const label patchSize, const word &patchName, const IOobject &io)
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:239
void reportMissingEntry(const word &entryName, const word &patchName, const IOobject &io) const
FatalError for missing entry.
#define FIELDSIZE_CHECK(fieldLen)
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
const keyType & keyword() const noexcept
Return keyword.
Definition: entry.H:231
void genericFatalSolveError(const word &patchName, const IOobject &io) const
Add error message to FatalError about solving with generic condition.
SymmTensor< scalar > symmTensor
SymmTensor of scalars, i.e. SymmTensor<scalar>.
Definition: symmTensor.H:55
A class for handling words, derived from Foam::string.
Definition: word.H:63
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:61
void processGeneric(const label patchSize, const word &patchName, const IOobject &io, const bool separateValue)
#define forAllIters(container, iter)
Iterate across all elements in the container object.
Definition: stdFoam.H:328
Vector< scalar > vector
Definition: vector.H:57
static constexpr direction nComponents
Number of components in this vector space.
Definition: VectorSpace.H:109
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:55
void rmapGeneric(const genericPatchFieldBase &rhs, const labelList &addr)
Implementation for reverse map given patch field onto this patch field.
OBJstream os(runTime.globalPath()/outputName)
Type & dynamicCast(U &obj)
A dynamic_cast (for references) that generates FatalError on failed casts.
Definition: typeInfo.H:108
Generic infrastructure for reading/writing unknown patch types.
void putEntry(const entry &e, Ostream &os) const
Write a single entry, with lookup of hashed values.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:607
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:58
SphericalTensor< scalar > sphericalTensor
SphericalTensor of scalars, i.e. SphericalTensor<scalar>.
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
genericPatchFieldBase()=default
Default construct, generally not useful.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...