caseInfo.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) 2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12  OpenFOAM is free software: you can redistribute it and/or modify it
13  under the terms of the GNU General Public License as published by
14  the Free Software Foundation, either version 3 of the License, or
15  (at your option) any later version.
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  You should have received a copy of the GNU General Public License
21  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
22 \*---------------------------------------------------------------------------*/
23 
24 #include "caseInfo.H"
25 #include "OFstream.H"
26 #include "fvMesh.H"
27 #include "cloud.H"
28 #include "globalMeshData.H"
29 #include "volFields.H"
30 #include "surfaceFields.H"
31 #include "processorFvPatch.H"
32 #include "JSONformatter.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace functionObjects
40 {
41  defineTypeNameAndDebug(caseInfo, 0);
42 
44  (
45  functionObject,
46  caseInfo,
47  dictionary
48  );
49 }
50 
51 const Enum<functionObjects::caseInfo::writeFormat>
52 Foam::functionObjects::caseInfo::writeFormatNames_
53 {
54  { writeFormat::dict, "dictionary" },
55  { writeFormat::json, "json" },
56 };
57 
58 const Enum<functionObjects::caseInfo::lookupMode>
59 Foam::functionObjects::caseInfo::lookupModeNames_
60 {
61  { lookupMode::none, "none" },
62  { lookupMode::warn, "warn" },
63  { lookupMode::error, "error" },
64 };
65 }
66 
67 
68 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
69 
70 void Foam::functionObjects::caseInfo::report(const string& str) const
71 {
72  switch (lookupMode_)
73  {
74  case lookupMode::warn:
75  {
76  Warning << str.c_str() << endl;
77  break;
78  }
79  case lookupMode::error:
80  {
81  FatalError << str.c_str() << exit(FatalError);
82  break;
83  }
84  case lookupMode::none:
85  {
86  break;
87  }
88  }
89 }
90 
91 
92 void Foam::functionObjects::caseInfo::processDict
93 (
94  dictionary& dict,
95  const dictionary& targetDict,
96  const entry* includePtr,
97  const entry* excludePtr
98 ) const
99 {
100  auto sanitise = [](const wordRe& w){
101  string str = w;
102  str.replaceAll("/", "_").replaceAll(".", "_");
103 
104  // Strip any leading "_"
105  while (str.starts_with('_'))
106  {
107  str = str.substr(1);
108  }
109  return str;
110  };
111 
112  if (includePtr)
113  {
114  const wordRes includeEntryNames(includePtr->stream());
115  for (const auto& nameRegex : includeEntryNames)
116  {
117  const auto* e = targetDict.findScoped(nameRegex, keyType::REGEX);
118  if (e)
119  {
120  if (nameRegex.contains('/') || nameRegex.contains('.'))
121  {
122  auto copyPtr = e->clone();
123  copyPtr->keyword() = sanitise(nameRegex);
124  dict.add(copyPtr.ptr());
125  }
126  else
127  {
128  dict.add(*e);
129  }
130  }
131  else
132  {
133  report
134  (
135  "Unable to find entry "
136  + nameRegex
137  + " in dictionary "
138  + targetDict.name()
139  );
140  }
141  }
142  }
143  else
144  {
145  if (excludePtr)
146  {
147  dictionary allData(targetDict);
148 
149  const wordRes excludeEntryNames(excludePtr->stream());
150 
151  for (const auto& nameRegex : excludeEntryNames)
152  {
153  const auto* e = allData.findScoped(nameRegex, keyType::REGEX);
154  if (e)
155  {
156  allData.remove(e->keyword());
157  }
158  }
159 
160  dict += allData;
161  }
162  else
163  {
164  // Add complete dictionary
165  dict += targetDict;
166  }
167  }
168 }
169 
170 
171 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
172 
173 void Foam::functionObjects::caseInfo::writeMeta(dictionary& out) const
174 {
175  out.add("case", time_.globalCaseName());
176  out.add("path", time_.globalPath());
177  out.add("regions", time_.sortedNames<fvMesh>());
178  out.add("nTimes", time_.times().size());
179  out.add("nProc", Pstream::nProcs());
180 }
181 
182 
184 (
185  const objectRegistry& obr,
186  dictionary& out,
187  dictionary& dictionaries
188 ) const
189 {
190  for (const auto& e : dictionaries)
191  {
192  const auto& keyword = e.keyword();
193 
194  if (!e.isDict())
195  {
196  FatalIOErrorInFunction(dictionaries)
197  << "Entries must be specified in dictionary format. Please "
198  << "correct entry " << keyword
199  << exit(FatalIOError);
200  }
201 
202  const dictionary& inputDict = e.dict();
203 
204  auto* includePtr = inputDict.findEntry("include");
205  auto* excludePtr = inputDict.findEntry("exclude");
206 
207  const auto* ePtr = inputDict.findEntry("name");
208 
209  if (ePtr)
210  {
211  const word name(ePtr->stream());
212  auto* dictPtr = obr.cfindObject<IOdictionary>(name);
213 
214  if (dictPtr)
215  {
216  processDict
217  (
218  out.subDictOrAdd(keyword),
219  *dictPtr,
220  includePtr,
221  excludePtr
222  );
223  dictionaries.remove(keyword);
224  }
225  }
226  }
227 }
228 
229 
231 (
232  dictionary& out,
233  dictionary& dictionaries
234 ) const
235 {
236  for (auto& e : dictionaries)
237  {
238  const auto& keyword = e.keyword();
239 
240  if (!e.isDict())
241  {
242  FatalIOErrorInFunction(dictionaries)
243  << "Entries must be specified in dictionary format. Please "
244  << "correct entry " << keyword
245  << exit(FatalIOError);
246  }
247 
248  const dictionary& inputDict = e.dict();
249 
250  auto* includePtr = inputDict.findEntry("include");
251  auto* excludePtr = inputDict.findEntry("exclude");
252 
253  const auto* ePtr = inputDict.findEntry("path");
254 
255  if (ePtr)
256  {
257  fileName path(ePtr->stream());
258  path.expand();
259 
260  IOobject io(path, time(), IOobject::MUST_READ);
261 
262  if (!io.typeHeaderOk<dictionary>(false))
263  {
264  continue;
265  }
266 
267  const word oldTypeName = IOdictionary::typeName;
268  const_cast<word&>(IOdictionary::typeName) = word::null;
269 
270  processDict
271  (
272  out.subDictOrAdd(keyword),
273  IOdictionary(io),
274  includePtr,
275  excludePtr
276  );
277 
278  const_cast<word&>(IOdictionary::typeName) = oldTypeName;
279 
280  dictionaries.remove(keyword);
281  }
282  }
283 }
284 
285 
287 (
288  dictionary& out
289 ) const
290 {
291  for (const auto& fo : functionObjectNames_)
292  {
294  if (getObjectResultDict(fo, dict))
295  {
296  out.add(fo, dict);
297  }
298  else
299  {
300  report("No result entries found for function object " + fo);
301  }
302  }
303 }
304 
305 
307 (
308  const polyMesh& mesh,
309  dictionary& dict
310 ) const
311 {
312  dict.add("nGeometricD", mesh.nGeometricD());
313  dict.add("nSolutionD", mesh.nSolutionD());
314 
315  const auto& globalData = mesh.globalData();
316 
317  dict.add("nPoints", globalData.nTotalPoints());
318  dict.add("nFaces", globalData.nTotalFaces());
319  dict.add("nCells", globalData.nTotalCells());
320 
321  dict.add("nPatches", mesh.boundaryMesh().nNonProcessor());
322 
323  dict.add("pointZones", mesh.pointZones().names());
324  dict.add("faceZones", mesh.faceZones().names());
325  dict.add("cellZones", mesh.cellZones().names());
326 
327  dict.add("boundsMin", mesh.bounds().min());
328  dict.add("boundsMax", mesh.bounds().max());
329 
330  dict.add("clouds", mesh.sortedNames<cloud>());
331 }
332 
333 
334 namespace Foam
335 {
336  template<class Type>
337  void addPatchTypeDetails(const fvMesh& mesh, dictionary& dict)
338  {
339  auto objects = mesh.lookupClass<Type>();
340  for (const auto* objPtr : objects)
341  {
342  if (objPtr->readOpt() == IOobject::MUST_READ)
343  {
344  const auto& bf = objPtr->boundaryField();
345  dictionary& objDict = dict.subDictOrAdd(objPtr->name());
346 
347  for (const auto& pf : bf)
348  {
349  if (!isA<processorFvPatch>(pf.patch()))
350  {
351  objDict.add(pf.patch().name(), pf.type());
352  }
353  }
354  }
355  }
356  }
357 
358  template<template<typename> class FieldType>
359  void addPatchDetails(const fvMesh& mesh, dictionary& dict)
360  {
361  addPatchTypeDetails<FieldType<scalar>>(mesh, dict);
362  addPatchTypeDetails<FieldType<vector>>(mesh, dict);
363  addPatchTypeDetails<FieldType<sphericalTensor>>(mesh, dict);
364  addPatchTypeDetails<FieldType<symmTensor>>(mesh, dict);
365  addPatchTypeDetails<FieldType<tensor>>(mesh, dict);
366  }
367 }
368 
369 
371 (
372  const fvMesh& mesh,
374 ) const
375 {
376  // Geometry
377  dictionary& bnd = dict.subDictOrAdd("types");
378  const auto& pbm = mesh.boundaryMesh();
379  for (const auto& pp : pbm)
380  {
381  if (!isA<processorPolyPatch>(pp))
382  {
383  bnd.add(pp.name(), pp.type());
384  }
385  }
386 
387  // Fields
388  dictionary& fld = dict.subDictOrAdd("fields");
389  addPatchDetails<VolumeField>(mesh, fld);
390  addPatchDetails<SurfaceField>(mesh, fld);
391  //addPatchDetails<AreaField>(mesh, fld);
392 }
393 
394 
395 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
396 
398 (
399  const word& name,
400  const Time& runTime,
401  const dictionary& dict
402 )
403 :
405  writeFile(runTime, name, typeName, dict),
406  writeFormat_(writeFormat::dict),
407  lookupMode_(lookupMode::warn)
408 {
409  read(dict);
410 }
411 
412 
413 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
414 
416 {
418  {
419  writeFormatNames_.readIfPresent("writeFormat", dict, writeFormat_);
420  lookupModeNames_.readIfPresent("lookupMode", dict, lookupMode_);
421 
422  dictionaries_ = dict.subOrEmptyDict("dictionaries");
423 
424  functionObjectNames_ =
425  dict.getOrDefault<wordList>("functionObjects", wordList());
426 
427  return true;
428  }
429 
430  return false;
431 }
432 
435 {
436  return true;
437 }
438 
439 
441 {
442  // Output dictionary
443  dictionary data;
444 
445  // Case meta data
446  writeMeta(data.subDictOrAdd("meta"));
447 
448  // Note: copying dictionaries
449  // - these are consumed/removed when found to enable checks that all
450  // dictionaries are processed
451  dictionary dicts(dictionaries_);
452 
453  dictionary& dataDicts = data.subDictOrAdd("dictionaries");
454 
455  // Time-registered dictionaries
456  writeRegisteredDicts(time_, dataDicts, dicts);
457 
458  // File-based dictionaries
459  writeFileDicts(dataDicts, dicts);
460 
461  // Per-region information
462  const auto meshes = time_.lookupClass<fvMesh>();
463  dictionary& regionDict = data.subDictOrAdd("regions");
464  for (const auto& iter : meshes.csorted())
465  {
466  dictionary meshDicts(dicts);
467 
468  const fvMesh& mesh = *iter.val();
469 
470  const word& name = mesh.name();
471 
472  dictionary& out = regionDict.subDictOrAdd(name);
473 
474  writeMeshStats(mesh, out.subDictOrAdd("mesh"));
475 
476  writePatches(mesh, out.subDictOrAdd("boundary"));
477 
478  // Mesh-registered dictionaries
479  writeRegisteredDicts(mesh, out.subDictOrAdd("dictionaries"), meshDicts);
480 
481  for (const word& keyword : meshDicts.sortedToc())
482  {
483  report
484  (
485  "Mesh '"
486  + keyword
487  + "' : Unable to process dictionary entry '"
488  + keyword
489  + "'"
490  );
491  }
492  }
493 
494 
495  writeFunctionObjects(data.subDictOrAdd("functions"));
496 
497 
498  if (Pstream::master())
499  {
500  auto filePtr = newFileAtTime(name(), time_.value());
501  auto& os = filePtr();
502 
503  // Reset stream width - was set in writeFile
504  os.width(0);
505 
506  switch (writeFormat_)
507  {
508  case writeFormat::dict:
509  {
510  os << data << endl;
511  break;
512  }
513  case writeFormat::json:
514  {
515  JSONformatter json(os);
516  json.writeDict(data);
517  break;
518  }
519  }
520 
521  Info<< "Written " << writeFormatNames_[writeFormat_]
522  << " file: " << os.name() << endl;
523  }
524 
525  return true;
526 }
527 
528 
529 // ************************************************************************* //
Foam::surfaceFields.
const polyBoundaryMesh & pbm
dictionary dict
defineTypeNameAndDebug(ObukhovLength, 0)
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:129
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:625
virtual bool read(const dictionary &dict)
Read the controls.
Definition: caseInfo.C:408
const Type * cfindObject(const word &name, const bool recursive=false) const
Return const pointer to the object of the given Type.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
virtual bool execute()
Execute, does nothing.
Definition: caseInfo.C:427
Macros for easy insertion into run-time selection tables.
dictionary & subDictOrAdd(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find and return a sub-dictionary for manipulation.
Definition: dictionary.C:481
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
bool remove(const word &keyword)
Remove an entry specified by keyword.
void writeMeshStats(const polyMesh &mesh, dictionary &dict) const
Write mesh statistics.
Definition: caseInfo.C:300
autoPtr< OFstream > filePtr
Definition: createFields.H:37
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
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
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
A cloud is a registry collection of lagrangian particles.
Definition: cloud.H:53
void writeMeta(dictionary &dict) const
Write case meta data.
Definition: caseInfo.C:166
caseInfo(const caseInfo &)=delete
No copy construct.
void writeRegisteredDicts(const objectRegistry &obr, dictionary &dict, dictionary &dictionaries) const
Write registered dictionaries.
Definition: caseInfo.C:177
Foam::PtrList< Foam::fvMesh > meshes(regionNames.size())
static const word null
An empty word.
Definition: word.H:84
void addPatchDetails(const fvMesh &mesh, dictionary &dict)
Definition: caseInfo.C:352
OBJstream os(runTime.globalPath()/outputName)
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
addToRunTimeSelectionTable(functionObject, ObukhovLength, dictionary)
virtual bool read(const dictionary &dict)
Read.
Definition: writeFile.C:241
void writePatches(const fvMesh &mesh, dictionary &dict) const
Write mesh patches.
Definition: caseInfo.C:364
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
List< word > wordList
List of word.
Definition: fileName.H:59
void writeFileDicts(dictionary &dict, dictionary &dictionaries) const
Write file-based dictionaries.
Definition: caseInfo.C:224
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
void writeFunctionObjects(dictionary &dict) const
Write function object results.
Definition: caseInfo.C:280
virtual bool read(const dictionary &dict)
Read and set the function object if its data have changed.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:84
Base class for function objects, adding functionality to read/write state information (data required ...
messageStream Info
Information stream (stdout output on master, null elsewhere)
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
Registry of regIOobjects.
Base class for writing single files from the function objects.
Definition: writeFile.H:112
void addPatchTypeDetails(const fvMesh &mesh, dictionary &dict)
Definition: caseInfo.C:330
Regular expression.
Definition: keyType.H:83
virtual bool write()
Write the caseInfo.
Definition: caseInfo.C:433
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...