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