foamUpgradeCyclics.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) 2011-2016 OpenFOAM Foundation
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 Application
28  foamUpgradeCyclics
29 
30 Group
31  grpPreProcessingUtilities
32 
33 Description
34  Tool to upgrade mesh and fields for split cyclics.
35 
36 Usage
37  \b foamUpgradeCyclics [OPTION]
38 
39  Options:
40  - \par -dry-run
41  Suppress writing the updated files with split cyclics
42 
43  - \par -enableFunctionEntries
44  By default all dictionary preprocessing of fields is disabled
45 
46 \*---------------------------------------------------------------------------*/
47 
48 #include "argList.H"
49 #include "Time.H"
50 #include "timeSelector.H"
51 #include "IOdictionary.H"
52 #include "polyMesh.H"
53 #include "entry.H"
54 #include "IOPtrList.H"
55 #include "cyclicPolyPatch.H"
56 #include "dictionaryEntry.H"
57 #include "IOobjectList.H"
58 #include "volFields.H"
59 #include "pointFields.H"
60 #include "surfaceFields.H"
61 #include "string.H"
62 
63 using namespace Foam;
64 
65 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
66 
67 namespace Foam
68 {
70 }
71 
72 
73 // Read boundary file without reading mesh
74 void rewriteBoundary
75 (
76  const bool dryrun,
77  const IOobject& io,
78  const fileName& regionPrefix,
79  HashTable<word>& thisNames,
80  HashTable<word>& nbrNames
81 )
82 {
83  Info<< "Reading boundary from " << typeFilePath<IOPtrList<entry>>(io)
84  << endl;
85 
86  // Read PtrList of dictionary.
87  const word oldTypeName = IOPtrList<entry>::typeName;
90  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
91  // Fake type back to what was in field
92  const_cast<word&>(patches.type()) = patches.headerClassName();
93 
94 
95  // Replace any 'cyclic'
96  label nOldCyclics = 0;
97  forAll(patches, patchi)
98  {
99  const dictionary& patchDict = patches[patchi].dict();
100 
101  if (patchDict.get<word>("type") == cyclicPolyPatch::typeName)
102  {
103  if (!patchDict.found("neighbourPatch"))
104  {
105  Info<< "Patch " << patches[patchi].keyword()
106  << " does not have 'neighbourPatch' entry; assuming it"
107  << " is of the old type." << endl;
108  nOldCyclics++;
109  }
110  }
111  }
112 
113  Info<< "Detected " << nOldCyclics << " old cyclics." << nl << endl;
114 
115 
116  // Save old patches.
117  PtrList<entry> oldPatches(patches);
118 
119  // Extend
120  label nOldPatches = patches.size();
121  patches.setSize(nOldPatches+nOldCyclics);
122 
123  // Create reordering map
124  labelList oldToNew(patches.size());
125 
126 
127  // Add new entries
128  label addedPatchi = nOldPatches;
129  label newPatchi = 0;
130  forAll(oldPatches, patchi)
131  {
132  const dictionary& patchDict = oldPatches[patchi].dict();
133 
134  if
135  (
136  patchDict.get<word>("type") == cyclicPolyPatch::typeName
137  )
138  {
139  const word& name = oldPatches[patchi].keyword();
140 
141  if (patchDict.found("neighbourPatch"))
142  {
143  patches.set(patchi, oldPatches.set(patchi, nullptr));
144  oldToNew[patchi] = newPatchi++;
145 
146  // Check if patches come from automatic conversion
147  word oldName;
148 
149  string::size_type i = name.rfind("_half0");
150  if (i != string::npos)
151  {
152  oldName = name.substr(0, i);
153  thisNames.insert(oldName, name);
154  Info<< "Detected converted cyclic patch " << name
155  << " ; assuming it originates from " << oldName
156  << endl;
157  }
158  else
159  {
160  i = name.rfind("_half1");
161  if (i != string::npos)
162  {
163  oldName = name.substr(0, i);
164  nbrNames.insert(oldName, name);
165  Info<< "Detected converted cyclic patch " << name
166  << " ; assuming it originates from " << oldName
167  << endl;
168  }
169  }
170  }
171  else
172  {
173  label nFaces = patchDict.get<label>("nFaces");
174  label startFace = patchDict.get<label>("startFace");
175 
176  Info<< "Detected old style " << patchDict.get<word>("type")
177  << " patch " << name << " with" << nl
178  << " nFaces : " << nFaces << nl
179  << " startFace : " << startFace << endl;
180 
181  word thisName = name + "_half0";
182  word nbrName = name + "_half1";
183 
184  thisNames.insert(name, thisName);
185  nbrNames.insert(name, nbrName);
186 
187  // Save current dictionary
188  const dictionary patchDict(patches[patchi].dict());
189 
190  // Change entry on this side
191  patches.set(patchi, oldPatches.set(patchi, nullptr));
192  oldToNew[patchi] = newPatchi++;
193  dictionary& thisPatchDict = patches[patchi].dict();
194  thisPatchDict.add("neighbourPatch", nbrName);
195  thisPatchDict.set("nFaces", nFaces/2);
196  patches[patchi].keyword() = thisName;
197 
198  // Add entry on other side
199  patches.set
200  (
201  addedPatchi,
202  new dictionaryEntry
203  (
204  nbrName,
206  patchDict
207  )
208  );
209  oldToNew[addedPatchi] = newPatchi++;
210  dictionary& nbrPatchDict = patches[addedPatchi].dict();
211  nbrPatchDict.set("neighbourPatch", thisName);
212  nbrPatchDict.set("nFaces", nFaces/2);
213  nbrPatchDict.set("startFace", startFace+nFaces/2);
214  patches[addedPatchi].keyword() = nbrName;
215 
216  Info<< "Replaced with patches" << nl
217  << patches[patchi].keyword() << " with" << nl
218  << " nFaces : "
219  << thisPatchDict.get<label>("nFaces") << nl
220  << " startFace : "
221  << thisPatchDict.get<label>("startFace") << nl
222  << patches[addedPatchi].keyword() << " with" << nl
223  << " nFaces : "
224  << nbrPatchDict.get<label>("nFaces") << nl
225  << " startFace : "
226  << nbrPatchDict.get<label>("startFace") << nl
227  << endl;
228 
229  addedPatchi++;
230  }
231  }
232  else
233  {
234  patches.set(patchi, oldPatches.set(patchi, nullptr));
235  oldToNew[patchi] = newPatchi++;
236  }
237  }
238 
239  patches.reorder(oldToNew);
240 
241  if (returnReduceOr(nOldCyclics))
242  {
243  if (dryrun)
244  {
245  //Info<< "-dry-run option: no changes made" << nl << endl;
246  }
247  else
248  {
249  if (mvBak(patches.objectPath(), "old"))
250  {
251  Info<< "Backup to "
252  << (patches.objectPath() + ".old") << nl;
253  }
254 
255  Info<< "Write to "
256  << patches.objectPath() << nl << endl;
257  patches.write();
258  }
259  }
260  else
261  {
262  Info<< "No changes made to boundary file." << nl << endl;
263  }
264 }
265 
266 
267 void rewriteField
268 (
269  const bool dryrun,
270  const Time& runTime,
271  const word& fieldName,
272  const HashTable<word>& thisNames,
273  const HashTable<word>& nbrNames
274 )
275 {
276  // Read dictionary. (disable class type checking so we can load
277  // field)
278  Info<< "Loading field " << fieldName << endl;
279  const word oldTypeName = IOdictionary::typeName;
280  const_cast<word&>(IOdictionary::typeName) = word::null;
281 
282  IOdictionary fieldDict
283  (
284  IOobject
285  (
286  fieldName,
287  runTime.timeName(),
288  runTime,
291  false
292  )
293  );
294  const_cast<word&>(IOdictionary::typeName) = oldTypeName;
295  // Fake type back to what was in field
296  const_cast<word&>(fieldDict.type()) = fieldDict.headerClassName();
297 
298 
299 
300  dictionary& boundaryField = fieldDict.subDict("boundaryField");
301 
302  bool hasChange = false;
303 
304  forAllConstIters(thisNames, iter)
305  {
306  const word& patchName = iter.key();
307  const word& newName = iter.val();
308 
309  Info<< "Looking for entry for patch " << patchName << endl;
310 
311  // Find old patch name either direct or through wildcards
312  // Find new patch name direct only
313 
314  if
315  (
316  boundaryField.found(patchName)
317  && !boundaryField.found(newName, keyType::LITERAL)
318  )
319  {
320  Info<< " Changing entry " << patchName << " to " << newName
321  << endl;
322 
323  dictionary& patchDict = boundaryField.subDict(patchName);
324 
325  if (patchDict.found("value"))
326  {
327  // Remove any value field since wrong size.
328  patchDict.remove("value");
329  }
330 
331 
332  boundaryField.changeKeyword(patchName, newName);
333  boundaryField.add
334  (
335  nbrNames[patchName],
336  patchDict
337  );
338  Info<< " Adding entry " << nbrNames[patchName] << endl;
339 
340  hasChange = true;
341  }
342  }
343 
344  //Info<< "New boundaryField:" << boundaryField << endl;
345 
346  if (returnReduceOr(hasChange))
347  {
348  if (dryrun)
349  {
350  //Info<< "-test option: no changes made" << endl;
351  }
352  else
353  {
354  if (mvBak(fieldDict.objectPath(), "old"))
355  {
356  Info<< "Backup to "
357  << (fieldDict.objectPath() + ".old") << nl;
358  }
359 
360  Info<< "Write to "
361  << fieldDict.objectPath() << endl;
362  fieldDict.regIOobject::write();
363  }
364  }
365  else
366  {
367  Info<< "No changes made to field " << fieldName << endl;
368  }
369  Info<< endl;
370 }
371 
372 
373 void rewriteFields
374 (
375  const bool dryrun,
376  const Time& runTime,
377  const wordList& fieldNames,
378  const HashTable<word>& thisNames,
379  const HashTable<word>& nbrNames
380 )
381 {
382  for (const word& fieldName : fieldNames)
383  {
384  rewriteField
385  (
386  dryrun,
387  runTime,
388  fieldName,
389  thisNames,
390  nbrNames
391  );
392  }
393 }
394 
395 
396 
397 int main(int argc, char *argv[])
398 {
400  (
401  "Tool to upgrade mesh and fields for split cyclics"
402  );
403 
405 
406  argList::addOptionCompat("dry-run", {"test", 1806});
408  (
409  "Test only do not change any files"
410  );
412  (
413  "enableFunctionEntries",
414  "Enable expansion of dictionary directives - #include, #codeStream etc"
415  );
416  #include "addRegionOption.H"
417 
418  #include "setRootCase.H"
419  #include "createTime.H"
420 
421 
422  // Make sure we do not use the master-only reading since we read
423  // fields (different per processor) as dictionaries.
425 
426 
428 
429  const bool dryrun = args.found("dry-run");
430  if (dryrun)
431  {
432  Info<< "-dry-run option: no changes made" << nl << endl;
433  }
434  const bool enableEntries = args.found("enableFunctionEntries");
435 
436  const word regionName =
438 
439  fileName regionPrefix;
441  {
442  regionPrefix = regionName;
443  }
444 
445 
446  // Per cyclic patch the new name for this side and the other side
447  HashTable<word> thisNames;
448  HashTable<word> nbrNames;
449 
450  // Rewrite constant boundary file. Return any patches that have been split.
451  IOobject io
452  (
453  "boundary",
454  runTime.constant(),
456  runTime,
459  false
460  );
461 
462  if (io.typeHeaderOk<IOPtrList<entry>>(false))
463  {
464  rewriteBoundary
465  (
466  dryrun,
467  io,
468  regionPrefix,
469  thisNames,
470  nbrNames
471  );
472  }
473 
474 
475 
476  // Convert any fields
477 
478  forAll(timeDirs, timeI)
479  {
480  runTime.setTime(timeDirs[timeI], timeI);
481 
482  Info<< "Time: " << runTime.timeName() << endl;
483 
484  // See if mesh in time directory
485  IOobject io
486  (
487  "boundary",
488  runTime.timeName(),
490  runTime,
493  false
494  );
495 
496  if (io.typeHeaderOk<IOPtrList<entry>>(false))
497  {
498  rewriteBoundary
499  (
500  dryrun,
501  io,
502  regionPrefix,
503  thisNames,
504  nbrNames
505  );
506  }
507 
508 
509  IOobjectList objects(runTime, runTime.timeName());
510 
511 
512  const int oldFlag = entry::disableFunctionEntries;
513  if (!enableEntries)
514  {
515  // By default disable dictionary expansion for fields
517  }
518 
519  // volFields
520  // ~~~~~~~~~
521 
522  rewriteFields
523  (
524  dryrun,
525  runTime,
527  thisNames,
528  nbrNames
529  );
530  rewriteFields
531  (
532  dryrun,
533  runTime,
535  thisNames,
536  nbrNames
537  );
538  rewriteFields
539  (
540  dryrun,
541  runTime,
543  thisNames,
544  nbrNames
545  );
546  rewriteFields
547  (
548  dryrun,
549  runTime,
551  thisNames,
552  nbrNames
553  );
554  rewriteFields
555  (
556  dryrun,
557  runTime,
559  thisNames,
560  nbrNames
561  );
562 
563 
564  // pointFields
565  // ~~~~~~~~~~~
566 
567  rewriteFields
568  (
569  dryrun,
570  runTime,
572  thisNames,
573  nbrNames
574  );
575  rewriteFields
576  (
577  dryrun,
578  runTime,
580  thisNames,
581  nbrNames
582  );
583  rewriteFields
584  (
585  dryrun,
586  runTime,
588  thisNames,
589  nbrNames
590  );
591  rewriteFields
592  (
593  dryrun,
594  runTime,
596  thisNames,
597  nbrNames
598  );
599  rewriteFields
600  (
601  dryrun,
602  runTime,
604  thisNames,
605  nbrNames
606  );
607 
608 
609  // surfaceFields
610  // ~~~~~~~~~~~
611 
612  rewriteFields
613  (
614  dryrun,
615  runTime,
617  thisNames,
618  nbrNames
619  );
620  rewriteFields
621  (
622  dryrun,
623  runTime,
625  thisNames,
626  nbrNames
627  );
628  rewriteFields
629  (
630  dryrun,
631  runTime,
633  thisNames,
634  nbrNames
635  );
636  rewriteFields
637  (
638  dryrun,
639  runTime,
641  thisNames,
642  nbrNames
643  );
644  rewriteFields
645  (
646  dryrun,
647  runTime,
649  thisNames,
650  nbrNames
651  );
652 
654  }
655 
656  return 0;
657 }
658 
659 
660 // ************************************************************************* //
Foam::surfaceFields.
bool mvBak(const fileName &src, const std::string &ext="bak")
Rename to a corresponding backup file.
Definition: POSIX.C:1310
dictionary dict
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:453
A class for handling file names.
Definition: fileName.H:71
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable, so the various sorted methods should be used if traversing in parallel.
Definition: IOobjectList.H:55
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:402
wordList names() const
The unsorted names of all objects.
void reorder(const labelUList &oldToNew, const bool validBoundary)
Reorders patches. Ordering does not have to be done in.
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:365
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:409
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:637
Ignore writing from objectRegistry::writeObject()
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:300
A keyword and a list of tokens is a &#39;dictionaryEntry&#39;.
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:453
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:239
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:100
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
bool remove(const word &keyword)
Remove an entry specified by keyword.
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:173
Foam::word regionName(Foam::polyMesh::defaultRegion)
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:139
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
A class for handling words, derived from Foam::string.
Definition: word.H:63
static void addDryRunOption(const string &usage, bool advanced=false)
Enable a &#39;dry-run&#39; bool option, with usage information.
Definition: argList.C:495
Reading required, file watched for runTime modification.
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:397
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:99
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition: dictionary.H:465
static const word null
An empty word.
Definition: word.H:84
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:977
String literal.
Definition: keyType.H:82
A HashTable similar to std::unordered_map.
Definition: HashTable.H:102
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:68
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:163
bool typeHeaderOk(const bool checkType=true, const bool search=true, const bool verbose=true)
Read header (uses typeFilePath to find file) and check its info.
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:760
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:89
defineTemplateTypeNameAndDebug(faScalarMatrix, 0)
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:313
static instantList select0(Time &runTime, const argList &args)
Return the set of times selected based on the argList options and also set the runTime to the first i...
Definition: timeSelector.C:234
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:183
const word typeName("volScalarField::Internal")
A PtrList of objects of type <T> with automated input and output.
Definition: IOPtrList.H:49
const word & headerClassName() const noexcept
Return name of the class name read from header.
Definition: IOobjectI.H:168
const polyBoundaryMesh & patches
messageStream Info
Information stream (stdout output on master, null elsewhere)
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:777
bool changeKeyword(const keyType &oldKeyword, const keyType &newKeyword, bool overwrite=false)
Change the keyword for an entry,.
virtual bool write(const bool valid=true) const
Write using setting from DB.
Foam::argList args(argc, argv)
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28