fvExprDriverTemplates.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) 2010-2018 Bernhard Gschaider
9  Copyright (C) 2019-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "surfaceMesh.H"
30 #include "fvsPatchField.H"
32 #include "typeInfo.H"
33 
34 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
35 
36 template<class Type>
38 (
39  const word& name,
40  const bool wantPointData,
41  const label expectedSize
42 ) const
43 {
44  DebugInfo
45  << "Looking for global" << (wantPointData ? " point" : "")
46  << " field name:" << name;
47 
49 
50  DebugInfo
51  << " - found (" << result.valueType() << ' '
52  << result.isPointData() << ')';
53 
54 
55  bool good =
56  (result.isType<Type>() && result.isPointData(wantPointData));
57 
58  // Do size checking if requested
59  if (good && expectedSize >= 0)
60  {
61  good = returnReduceAnd(result.size() == expectedSize);
62 
63  if (debug && !good)
64  {
65  Info<< " size is";
66  }
67  }
68 
69  DebugInfo << (good ? " good" : " bad") << endl;
70 
71  return good;
72 }
73 
74 
75 template<class Type>
78 (
79  const word& name,
80  const label expectedSize,
81  const bool mandatory
82 ) const
83 {
85 
86  if (hasVariable(name) && variable(name).isType<Type>())
87  {
88  tvar.cref(variable(name));
89  }
90  else if (isGlobalVariable<Type>(name))
91  {
92  tvar.cref(lookupGlobal(name));
93  }
94 
95 
96  if (tvar.valid())
97  {
98  const auto& var = tvar.cref();
99 
100  const Field<Type>& vals = var.cref<Type>();
101 
102  if
103  (
104  expectedSize < 0
105  || returnReduceAnd(vals.size() == expectedSize)
106  )
107  {
108  // Return a copy of the field
109  return tmp<Field<Type>>::New(vals);
110  }
111 
112  if (!var.isUniform())
113  {
115  << "Variable " << name
116  << " is nonuniform and does not fit the size "
117  << expectedSize << ". Using average" << endl;
118  }
119 
120  return tmp<Field<Type>>::New(expectedSize, gAverage(vals));
121  }
122 
123  if (mandatory)
124  {
126  << "Variable (" << name << ") not found." << nl
127  << exit(FatalError);
128  }
130  return nullptr;
131 }
132 
133 
134 template<class Type>
136 (
137  const word& name
138 ) const
139 {
140  if (debug)
141  {
142  Info<< "fvExprDriver::foundField. Name: " << name
143  << " Type: " << Type::typeName
144  << " registry:" << searchRegistry()
145  << " disk:" << searchFiles() << endl;
146  }
147 
148 
149  for (int checki = 0; checki < 2; ++checki)
150  {
151  // Check 0: object context (first)
152  // Check 1: regular objectRegistry
153  const regIOobject* ioptr = nullptr;
154 
155  if (checki == 0)
156  {
158  }
159  else if (searchRegistry())
160  {
161  ioptr = this->mesh().cfindIOobject(name);
162  }
163  if (!ioptr) continue;
164 
165  const Type* fldPtr = dynamic_cast<const Type*>(ioptr);
166 
167  if (fldPtr)
168  {
169  if (debug)
170  {
171  if (checki)
172  {
173  Info<< "Found registered:";
174  }
175  else
176  {
177  Info<< "Found context object:";
178  }
179  Info<< name << endl;
180  }
181  return true;
182  }
183  else if (ioptr)
184  {
185  if (debug)
186  {
187  if (checki)
188  {
189  Info<< "Registered:";
190  }
191  else
192  {
193  Info<< "Context object:";
194  }
195  Info<< name << " type:"
196  << ioptr->headerClassName() << " != type:"
197  << Type::typeName << nl;
198  }
199  }
200  }
201 
202 
203  if (searchFiles() && getTypeOfField(name) == Type::typeName)
204  {
205  if (debug)
206  {
207  Info<< "Found file: " << name << nl;
208  }
209  return true;
210  }
211 
212  if (debug)
213  {
214  Info<< name << " not found" << endl;
215  }
216  return false;
217 }
218 
219 
220 template<class Type>
222 (
223  const word& name,
224  bool wantPointData,
225  label
226 ) const
227 {
228  if (debug)
229  {
230  Info<< "fvExprDriver::isField <" << name << '>' << endl;
231  }
232 
233  return
234  (
235  wantPointData
236  ? this->foundField<PointField<Type>>(name)
237  :
238  (
239  this->foundField<VolumeField<Type>>(name)
240  || this->foundField<SurfaceField<Type>>(name)
241  )
242  );
243 }
244 
245 
246 template<class GeomField, class Mesh>
247 Foam::tmp<GeomField> Foam::expressions::fvExprDriver::getOrReadFieldImpl
248 (
249  const word& name,
250  const Mesh& meshRef,
251  bool mandatory,
252  bool getOldTime
253 )
254 {
255  typedef typename GeomField::value_type Type;
256 
257  tmp<GeomField> tfield;
258 
259  if (debug)
260  {
261  Info<< "fvExprDriver::getOrReadField <" << name
262  << "> Type: " << GeomField::typeName << endl;
263  }
264 
265 
266  // Handle variables
267  // ~~~~~~~~~~~~~~~~
268 
269  refPtr<expressions::exprResult> tvar;
270 
271  if (hasVariable(name) && variable(name).isType<Type>())
272  {
273  tvar.cref(variable(name));
274  }
275  else if (isGlobalVariable<Type>(name))
276  {
277  tvar.cref(lookupGlobal(name));
278  }
279 
280  if (tvar.valid())
281  {
282  const auto& var = tvar.cref();
283  const Type deflt(var.getValue<Type>());
284 
285  if (debug)
286  {
287  Info<< "Getting " << name << " from variables. Default: "
288  << deflt << endl;
289  }
290 
291  if (debug)
292  {
293  Info<< "Creating field " << name << " of type "
294  << GeomField::typeName << nl;
295  }
296 
297  tfield = GeomField::New
298  (
299  name,
300  meshRef,
301  dimensioned<Type>(deflt),
302  // Patch is zeroGradient (volFields) or calculated (other)
303  defaultBoundaryType(GeomField::null())
304  );
305  auto& fld = tfield.ref();
306 
307  if (debug)
308  {
309  Info<< "New field: " << name << " ownedByRegistry"
310  << fld.ownedByRegistry() << endl;
311  }
312 
313  const Field<Type>& vals = var.cref<Type>();
314 
315  if (debug)
316  {
317  Pout<< "sizes: " << vals.size() << ' ' << fld.size() << endl;
318  }
319 
320  if (returnReduceAnd(vals.size() == fld.size()))
321  {
322  fld.primitiveFieldRef() = vals;
323  }
324  else
325  {
326  const Type avg = gAverage(vals);
327 
328  bool noWarn = false;
329 
330  if (!noWarn)
331  {
332  MinMax<Type> range = gMinMax(vals);
333 
334  if (range.mag() > SMALL)
335  {
336  WarningInFunction
337  << "The min/max ranges differ " << range
338  << " - using average " << avg << nl;
339  }
340  }
341 
342  fld.primitiveFieldRef() = avg;
343  }
344 
345  correctField(fld);
346 
347  return tfield;
348  }
349 
350 
351  // Find context or registered field
352  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
353 
354  const GeomField* origFldPtr = nullptr;
355 
356  for (int checki = 0; !origFldPtr && checki < 2; ++checki)
357  {
358  // Check 0: object context (first)
359  // Check 1: regular objectRegistry
360 
361  if (checki == 0)
362  {
363  origFldPtr = exprDriver::cfindContextObject<GeomField>(name);
364  }
365  else if (searchRegistry())
366  {
367  origFldPtr =
368  meshRef.thisDb().template cfindObject<GeomField>(name);
369  }
370  }
371 
372  if (origFldPtr)
373  {
374  // Found from context or registry
375 
376  if (debug)
377  {
378  Info<< "Retrieve context/registered:" << name << nl;
379  }
380 
381  const GeomField& origFld = *origFldPtr;
382 
383  // Make a deep copy of the data to return. Avoids shadowing
384  // the original object, but most importantly the backend
385  // parser (eg, lemon) will be working with combining via plain
386  // pointers. We thus lose any of the tmp<> shallow copy semantics
387  // anyhow. Additionally, need to disable dimension checking here or
388  // elsewhere too.
389 
390  tfield = GeomField::New(name + "_exprDriverCopy", origFld);
391 
392  if (getOldTime)
393  {
394  if (debug)
395  {
396  Info<< "Getting oldTime of " << name << " has "
397  << origFld.nOldTimes() << endl;
398  }
399 
400  if (!origFld.nOldTimes() && this->prevIterIsOldTime())
401  {
402  if (debug)
403  {
404  Info<< "No oldTime, using previous iteration" << endl;
405  }
406  tfield.ref().oldTime() = origFld.prevIter();
407  }
408  }
409  }
410  else if (searchFiles() && getTypeOfField(name) == GeomField::typeName)
411  {
412  if (debug)
413  {
414  Info<< "Reading " << name << " from disc" << endl;
415  }
416 
417  tfield.reset
418  (
419  this->readAndRegister<GeomField>(name, meshRef)
420  );
421  // oldTime automatically read
422  }
423 
424 
425  if (debug)
426  {
427  Info<< "field: valid()=" << Switch::name(tfield.valid()) << endl;
428  }
429 
430  if (tfield.valid())
431  {
432  GeomField& fld = tfield.ref();
433 
434  if (debug)
435  {
436  Info<< "Valid " << name << " found. Removing dimensions" << nl;
437  }
438 
439  fld.dimensions().clear();
440 
441  if (fld.nOldTimes())
442  {
443  if (debug)
444  {
445  Info<< "Removing dimensions of oldTime of " << name
446  << " has " << fld.nOldTimes() << nl;
447  }
448 
449  // Switch dimension checking off
450  const bool oldDimChecking = dimensionSet::checking(false);
451 
452  // go through ALL old times
453  GeomField* fp = &(fld);
454 
455  while (fp->nOldTimes())
456  {
457  fp = &(fp->oldTime());
458  fp->dimensions().clear();
459  }
460 
461  // Restore old value of dimension checking
462  dimensionSet::checking(oldDimChecking);
463  }
464  }
465  else if (mandatory)
466  {
467  FatalErrorInFunction
468  << "Could not find field " << name
469  << " in registry or on file-system" << nl
470  << exit(FatalError);
471  }
473  return tfield;
474 }
475 
476 
477 template<class T>
478 Foam::autoPtr<T> Foam::expressions::fvExprDriver::getTopoSet
479 (
480  const fvMesh& mesh,
481  const word& name,
482  SetOrigin& origin
483 ) const
484 {
485  // Avoid possible name clashes
486  const word regName = name + "RegisteredNameFor" + T::typeName;
487 
488  if (debug)
489  {
490  Info<< "Looking for " << T::typeName << " named " << name
491  << " or registered as " << regName << " with mesh "
492  << "Caching:" << cacheSets()
493  << " Found:" << (mesh.foundObject<T>(name))
494  << " Found registered:" << mesh.foundObject<T>(regName)
495  << endl;
496  }
497 
498 
499  origin = SetOrigin::INVALID;
500  autoPtr<T> setPtr;
501 
502  if
503  (
504  !cacheSets()
505  ||
506  (
507  !mesh.thisDb().foundObject<T>(regName)
508  && !mesh.thisDb().foundObject<T>(name)
509  )
510  )
511  {
512  if (debug)
513  {
514  Info<< "Constructing new " << T::typeName << ' ' << name << nl;
515 
516  if (debug > 1)
517  {
518  Pout<< mesh.thisDb().names();
519  }
520  }
521 
522  origin = SetOrigin::FILE;
523  setPtr.reset(new T(mesh, name, IOobject::MUST_READ));
524 
525  if (cacheSets())
526  {
527  if (debug)
528  {
529  Info<< "Registering a copy of " << name << " with mesh" << nl;
530  }
531 
532  autoPtr<T> toCache(new T(mesh, regName, *setPtr));
533  toCache->store(toCache);
534  }
535  }
536  else
537  {
538  const T* ptr = mesh.thisDb().template cfindObject<T>(name);
539 
540  if (ptr)
541  {
542  if (debug)
543  {
544  Info<< "Getting existing " << name << endl;
545  }
546 
547  origin = SetOrigin::MEMORY;
548  setPtr.reset(new T(mesh, name, *ptr));
549  }
550  else
551  {
552  if (debug)
553  {
554  Info<< "Getting existing " << regName << endl;
555  }
556 
557  origin = SetOrigin::CACHE;
558  setPtr.reset(new T(mesh, name, mesh.lookupObject<T>(regName)));
559  }
560  }
561 
563  return setPtr;
564 }
565 
566 
567 template<class T>
568 bool Foam::expressions::fvExprDriver::updateSet
569 (
570  autoPtr<T>& setPtr,
571  const word& name,
572  SetOrigin origin
573 ) const
574 {
575  const label oldSize = setPtr->size();
576 
577  bool updated = false;
578  const auto& mesh = refCast<const polyMesh>(setPtr->db());
579 
580  if (debug)
581  {
582  Info<< "UpdateSet: " << setPtr->name() << " Id: " << name
583  << " Origin: " << int(origin) << endl;
584  }
585 
586  switch (origin)
587  {
588  case SetOrigin::FILE:
589  {
590  IOobject header
591  (
592  name,
593  mesh.time().timeName(),
594  polyMesh::meshSubDir/"sets",
595  mesh,
596  IOobject::MUST_READ,
597  IOobject::NO_WRITE
598  );
599 
600  if (header.typeHeaderOk<T>())
601  {
602  if (debug)
603  {
604  Pout<< "Rereading from "
605  << header.localFilePath(T::typeName) << endl;
606  }
607  setPtr.reset(new T(header));
608  updated = true;
609  }
610  break;
611  }
612 
613  case SetOrigin::NEW:
614  case SetOrigin::MEMORY:
615  case SetOrigin::CACHE:
616  {
617  if (origin == SetOrigin::NEW)
618  {
619  WarningInFunction
620  << "State NEW shouldn't exist"
621  << endl;
622  }
623 
624  word sName = name;
625 
626  const T* ptr = mesh.thisDb().template cfindObject<T>(name);
627 
628  if (ptr)
629  {
630  if (debug)
631  {
632  Info<< "Found " << name
633  << " and rereading it" << endl;
634  }
635 
636  setPtr.reset(new T(mesh, name, *ptr));
637  }
638  else
639  {
640  FatalErrorInFunction
641  << name << " Not found" << endl
642  << "In registry: " << mesh.thisDb().names() << endl
643  << exit(FatalError);
644  }
645  updated = true;
646  break;
647  }
648 
649  case INVALID:
650  {
651  FatalErrorInFunction
652  << T::typeName << ' ' << name << " is invalid" << endl
653  << exit(FatalError);
654  break;
655  }
656 
657  default:
658  {
659  if (debug)
660  {
661  Info<< "Origin " << int(origin) << " not implemented" << endl;
662  }
663  break;
664  }
665  }
666 
667  if (debug)
668  {
669  Pout<< name << " old size " << oldSize << " new: "
670  << setPtr->size() << endl;
671  }
672 
673  return updated;
674 }
675 
676 
677 // ************************************************************************* //
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...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
A polymorphic field/result from evaluating an expression.
Definition: exprResult.H:121
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool isType() const
True if valueType corresponds to the given Type.
Definition: exprResultI.H:214
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
bool isField(const word &name, const bool wantPointData=false, const label expectSize=-1) const
Test for the existence of a mesh field.
bool valid() const noexcept
Identical to good(), or bool operator.
Definition: refPtr.H:512
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
const regIOobject * cfindContextIOobject(const word &name) const
Find named context field, if it exists.
const word & valueType() const noexcept
Basic type for the field or single value.
Definition: exprResultI.H:192
const T & cref() const
Return const reference to the object or to the contents of a (non-null) managed pointer.
Definition: refPtrI.H:216
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A class for handling words, derived from Foam::string.
Definition: word.H:63
bool isGlobalVariable(const word &name, const bool wantPointData=false, const label expectedSize=-1) const
Test existence of a global variable.
const exprResult & result() const noexcept
Const access to expression result.
Definition: exprDriver.H:483
tmp< Field< Type > > getVariable(const word &name, const label expectSize, const bool mandatory=true) const
Retrieve local/global variable as a tmp field.
#define DebugInfo
Report an information message using Foam::Info.
int debug
Static debugging option.
const word & headerClassName() const noexcept
Return name of the class name read from header.
Definition: IOobjectI.H:213
label size() const
The field or object size.
Definition: exprResultI.H:252
#define WarningInFunction
Report a warning using Foam::Warning.
Type gAverage(const FieldField< Field, Type > &f)
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition: regIOobject.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
const exprResult & lookupGlobal(const word &name) const
Return the global variable if available or a null result.
Definition: fvExprDriver.C:695
bool isPointData(const bool wantPointData=true) const
True if representing point data, or test for same value as wantPointData argument.
Definition: exprResultI.H:199
A class for managing temporary objects.
Definition: HashPtrTable.H:50
bool foundField(const word &name) const
Test if specified field can be found in memory or disk.
bool found