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-2024 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 "caseInfo.H"
29 #include "OFstream.H"
30 #include "fvMesh.H"
31 #include "cloud.H"
32 #include "globalMeshData.H"
33 #include "volFields.H"
34 #include "surfaceFields.H"
35 #include "processorFvPatch.H"
36 #include "JSONformatter.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43 namespace functionObjects
44 {
45  defineTypeNameAndDebug(caseInfo, 0);
46 
48  (
49  functionObject,
50  caseInfo,
51  dictionary
52  );
53 }
54 
55 const Enum<functionObjects::caseInfo::writeFormat>
56 Foam::functionObjects::caseInfo::writeFormatNames_
57 {
58  { writeFormat::dict, "dictionary" },
59  { writeFormat::json, "json" },
60 };
61 
62 const Enum<functionObjects::caseInfo::lookupMode>
63 Foam::functionObjects::caseInfo::lookupModeNames_
64 {
65  { lookupMode::none, "none" },
66  { lookupMode::warn, "warn" },
67  { lookupMode::error, "error" },
68 };
69 }
70 
71 
72 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
73 
74 void Foam::functionObjects::caseInfo::report(const string& str) const
75 {
76  switch (lookupMode_)
77  {
78  case lookupMode::warn:
79  {
80  Warning << str.c_str() << endl;
81  break;
82  }
83  case lookupMode::error:
84  {
85  FatalError << str.c_str() << exit(FatalError);
86  break;
87  }
88  case lookupMode::none:
89  {
90  break;
91  }
92  }
93 }
94 
95 
96 void Foam::functionObjects::caseInfo::processDict
97 (
98  dictionary& dict,
99  const dictionary& targetDict,
100  const entry* includePtr,
101  const entry* excludePtr
102 ) const
103 {
104  auto sanitise = [](const wordRe& w){
105  string str = w;
106  str.replaceAll("/", "_").replaceAll(".", "_");
107 
108  // Strip any leading "_"
109  while (str.starts_with('_'))
110  {
111  str = str.substr(1);
112  }
113  return str;
114  };
115 
116  if (includePtr)
117  {
118  const wordRes includeEntryNames(includePtr->stream());
119  for (const auto& nameRegex : includeEntryNames)
120  {
121  const auto* e = targetDict.findScoped(nameRegex, keyType::REGEX);
122  if (e)
123  {
124  if (nameRegex.contains('/') || nameRegex.contains('.'))
125  {
126  auto copyPtr = e->clone();
127  copyPtr->keyword() = sanitise(nameRegex);
128  dict.add(copyPtr.ptr());
129  }
130  else
131  {
132  dict.add(*e);
133  }
134  }
135  else
136  {
137  report
138  (
139  "Unable to find entry "
140  + nameRegex
141  + " in dictionary "
142  + targetDict.name()
143  );
144  }
145  }
146  }
147  else
148  {
149  if (excludePtr)
150  {
151  dictionary allData(targetDict);
152 
153  const wordRes excludeEntryNames(excludePtr->stream());
154 
155  for (const auto& nameRegex : excludeEntryNames)
156  {
157  const auto* e = allData.findScoped(nameRegex, keyType::REGEX);
158  if (e)
159  {
160  allData.remove(e->keyword());
161  }
162  }
163 
164  dict += allData;
165  }
166  else
167  {
168  // Add complete dictionary
169  dict += targetDict;
170  }
171  }
172 }
173 
174 
175 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
176 
177 void Foam::functionObjects::caseInfo::writeMeta(dictionary& out) const
178 {
179  out.add("case", time_.globalCaseName());
180  out.add("path", time_.globalPath());
181  out.add("regions", time_.sortedNames<fvMesh>());
182  out.add("nTimes", time_.times().size());
183  out.add("nProc", Pstream::nProcs());
184 }
185 
186 
188 (
189  const objectRegistry& obr,
190  dictionary& out,
191  dictionary& dictionaries
192 ) const
193 {
194  for (const auto& e : dictionaries)
195  {
196  const auto& keyword = e.keyword();
197 
198  if (!e.isDict())
199  {
200  FatalIOErrorInFunction(dictionaries)
201  << "Entries must be specified in dictionary format. Please "
202  << "correct entry " << keyword
203  << exit(FatalIOError);
204  }
205 
206  const dictionary& inputDict = e.dict();
207 
208  auto* includePtr = inputDict.findEntry("include");
209  auto* excludePtr = inputDict.findEntry("exclude");
210 
211  const auto* ePtr = inputDict.findEntry("name");
212 
213  if (ePtr)
214  {
215  const word name(ePtr->stream());
216  auto* dictPtr = obr.cfindObject<IOdictionary>(name);
217 
218  if (dictPtr)
219  {
220  processDict
221  (
222  out.subDictOrAdd(keyword),
223  *dictPtr,
224  includePtr,
225  excludePtr
226  );
227  dictionaries.remove(keyword);
228  }
229  }
230  }
231 }
232 
233 
235 (
236  dictionary& out,
237  dictionary& dictionaries
238 ) const
239 {
240  for (auto& e : dictionaries)
241  {
242  const auto& keyword = e.keyword();
243 
244  if (!e.isDict())
245  {
246  FatalIOErrorInFunction(dictionaries)
247  << "Entries must be specified in dictionary format. Please "
248  << "correct entry " << keyword
249  << exit(FatalIOError);
250  }
251 
252  const dictionary& inputDict = e.dict();
253 
254  auto* includePtr = inputDict.findEntry("include");
255  auto* excludePtr = inputDict.findEntry("exclude");
256 
257  const auto* ePtr = inputDict.findEntry("path");
258 
259  if (ePtr)
260  {
261  fileName path(ePtr->stream());
262  path.expand();
263 
264  IOobject io(path, time(), IOobject::MUST_READ);
265 
266  if (!io.typeHeaderOk<dictionary>(false))
267  {
268  continue;
269  }
270 
271  const word oldTypeName = IOdictionary::typeName;
272  const_cast<word&>(IOdictionary::typeName) = word::null;
273 
274  processDict
275  (
276  out.subDictOrAdd(keyword),
277  IOdictionary(io),
278  includePtr,
279  excludePtr
280  );
281 
282  const_cast<word&>(IOdictionary::typeName) = oldTypeName;
283 
284  dictionaries.remove(keyword);
285  }
286  }
287 }
288 
289 
291 (
292  dictionary& out
293 ) const
294 {
295  for (const auto& fo : functionObjectNames_)
296  {
298  if (getObjectResultDict(fo, dict))
299  {
300  out.add(fo, dict);
301  }
302  else
303  {
304  report("No result entries found for function object " + fo);
305  }
306  }
307 }
308 
309 
311 (
312  const polyMesh& mesh,
313  dictionary& dict
314 ) const
315 {
316  dict.add("nGeometricD", mesh.nGeometricD());
317  dict.add("nSolutionD", mesh.nSolutionD());
318 
319  const auto& globalData = mesh.globalData();
320 
321  dict.add("nPoints", globalData.nTotalPoints());
322  dict.add("nFaces", globalData.nTotalFaces());
323  dict.add("nCells", globalData.nTotalCells());
324 
325  dict.add("nPatches", mesh.boundaryMesh().nNonProcessor());
326 
327  dict.add("pointZones", mesh.pointZones().names());
328  dict.add("faceZones", mesh.faceZones().names());
329  dict.add("cellZones", mesh.cellZones().names());
330 
331  dict.add("boundsMin", mesh.bounds().min());
332  dict.add("boundsMax", mesh.bounds().max());
333 
334  dict.add("clouds", mesh.sortedNames<cloud>());
335 }
336 
337 
338 namespace Foam
339 {
340  template<class GeoFieldType>
341  void addPatchTypeDetails(const fvMesh& mesh, dictionary& dict)
342  {
343  for (const GeoFieldType& obj : mesh.csorted<GeoFieldType>())
344  {
345  if (obj.readOpt() == IOobject::MUST_READ)
346  {
347  const auto& bf = obj.boundaryField();
348  dictionary& objDict = dict.subDictOrAdd(obj.name());
349 
350  for (const auto& pf : bf)
351  {
352  if (!isA<processorFvPatch>(pf.patch()))
353  {
354  objDict.add(pf.patch().name(), pf.type());
355  }
356  }
357  }
358  }
359  }
360 
361  template<template<typename> class FieldType>
362  void addPatchDetails(const fvMesh& mesh, dictionary& dict)
363  {
364  addPatchTypeDetails<FieldType<scalar>>(mesh, dict);
365  addPatchTypeDetails<FieldType<vector>>(mesh, dict);
366  addPatchTypeDetails<FieldType<sphericalTensor>>(mesh, dict);
367  addPatchTypeDetails<FieldType<symmTensor>>(mesh, dict);
368  addPatchTypeDetails<FieldType<tensor>>(mesh, dict);
369  }
370 }
371 
372 
374 (
375  const fvMesh& mesh,
377 ) const
378 {
379  // Geometry
380  dictionary& bnd = dict.subDictOrAdd("types");
381  const auto& pbm = mesh.boundaryMesh();
382  for (const auto& pp : pbm)
383  {
384  if (!isA<processorPolyPatch>(pp))
385  {
386  bnd.add(pp.name(), pp.type());
387  }
388  }
389 
390  // Fields
391  dictionary& fld = dict.subDictOrAdd("fields");
392  addPatchDetails<VolumeField>(mesh, fld);
393  addPatchDetails<SurfaceField>(mesh, fld);
394  //addPatchDetails<AreaField>(mesh, fld);
395 }
396 
397 
398 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
399 
401 (
402  const word& name,
403  const Time& runTime,
404  const dictionary& dict
405 )
406 :
408  writeFile(runTime, name, typeName, dict),
409  writeFormat_(writeFormat::dict),
410  lookupMode_(lookupMode::warn)
411 {
412  read(dict);
413 }
414 
415 
416 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
417 
419 {
421  {
422  writeFormatNames_.readIfPresent("writeFormat", dict, writeFormat_);
423  lookupModeNames_.readIfPresent("lookupMode", dict, lookupMode_);
424 
425  dictionaries_ = dict.subOrEmptyDict("dictionaries");
426 
427  functionObjectNames_ =
428  dict.getOrDefault<wordList>("functionObjects", wordList());
429 
430  return true;
431  }
432 
433  return false;
434 }
435 
438 {
439  return true;
440 }
441 
442 
444 {
445  // Output dictionary
446  dictionary data;
447 
448  // Case meta data
449  writeMeta(data.subDictOrAdd("meta"));
450 
451  // Note: copying dictionaries
452  // - these are consumed/removed when found to enable checks that all
453  // dictionaries are processed
454  dictionary dicts(dictionaries_);
455 
456  dictionary& dataDicts = data.subDictOrAdd("dictionaries");
457 
458  // Time-registered dictionaries
459  writeRegisteredDicts(time_, dataDicts, dicts);
460 
461  // File-based dictionaries
462  writeFileDicts(dataDicts, dicts);
463 
464  // Per-region information
465  dictionary& regionDict = data.subDictOrAdd("regions");
466 
467  for (const fvMesh& mesh : time_.csorted<fvMesh>())
468  {
469  dictionary meshDicts(dicts);
470 
471  const word& name = mesh.name();
472 
473  dictionary& out = regionDict.subDictOrAdd(name);
474 
475  writeMeshStats(mesh, out.subDictOrAdd("mesh"));
476 
477  writePatches(mesh, out.subDictOrAdd("boundary"));
478 
479  // Mesh-registered dictionaries
480  writeRegisteredDicts(mesh, out.subDictOrAdd("dictionaries"), meshDicts);
481 
482  for (const word& keyword : meshDicts.sortedToc())
483  {
484  report
485  (
486  "Mesh '"
487  + keyword
488  + "' : Unable to process dictionary entry '"
489  + keyword
490  + "'"
491  );
492  }
493  }
494 
495 
496  writeFunctionObjects(data.subDictOrAdd("functions"));
497 
498 
499  if (Pstream::master())
500  {
501  auto filePtr = newFileAtTime(name(), time_.value());
502  auto& os = filePtr();
503 
504  // Reset stream width - was set in writeFile
505  os.width(0);
506 
507  switch (writeFormat_)
508  {
509  case writeFormat::dict:
510  {
511  os << data << endl;
512  break;
513  }
514  case writeFormat::json:
515  {
516  JSONformatter json(os);
517  json.writeDict(data);
518  break;
519  }
520  }
521 
522  Info<< "Written " << writeFormatNames_[writeFormat_]
523  << " file: " << os.name() << endl;
524  }
525 
526  return true;
527 }
528 
529 
530 // ************************************************************************* //
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:411
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:430
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:304
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:1077
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:170
caseInfo(const caseInfo &)=delete
No copy construct.
void writeRegisteredDicts(const objectRegistry &obr, dictionary &dict, dictionary &dictionaries) const
Write registered dictionaries.
Definition: caseInfo.C:181
static const word null
An empty word.
Definition: word.H:84
void addPatchDetails(const fvMesh &mesh, dictionary &dict)
Definition: caseInfo.C:355
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:367
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:228
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:637
void writeFunctionObjects(dictionary &dict) const
Write function object results.
Definition: caseInfo.C:284
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:1094
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:334
Regular expression.
Definition: keyType.H:83
virtual bool write()
Write the caseInfo.
Definition: caseInfo.C:436
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 ...