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-2020 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 (returnReduce(nOldCyclics, sumOp<label>()) > 0)
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  label nChanged = 0;
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  nChanged++;
341  }
342  }
343 
344  //Info<< "New boundaryField:" << boundaryField << endl;
345 
346  if (returnReduce(nChanged, sumOp<label>()) > 0)
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  "dry-run",
410  "Test only do not change any files"
411  );
413  (
414  "enableFunctionEntries",
415  "Enable expansion of dictionary directives - #include, #codeStream etc"
416  );
417  #include "addRegionOption.H"
418 
419  #include "setRootCase.H"
420  #include "createTime.H"
421 
422 
423  // Make sure we do not use the master-only reading since we read
424  // fields (different per processor) as dictionaries.
426 
427 
429 
430  const bool dryrun = args.found("dry-run");
431  if (dryrun)
432  {
433  Info<< "-dry-run option: no changes made" << nl << endl;
434  }
435  const bool enableEntries = args.found("enableFunctionEntries");
436 
437  const word regionName =
439 
440  fileName regionPrefix;
442  {
443  regionPrefix = regionName;
444  }
445 
446 
447  // Per cyclic patch the new name for this side and the other side
448  HashTable<word> thisNames;
449  HashTable<word> nbrNames;
450 
451  // Rewrite constant boundary file. Return any patches that have been split.
452  IOobject io
453  (
454  "boundary",
455  runTime.constant(),
457  runTime,
460  false
461  );
462 
463  if (io.typeHeaderOk<IOPtrList<entry>>(false))
464  {
465  rewriteBoundary
466  (
467  dryrun,
468  io,
469  regionPrefix,
470  thisNames,
471  nbrNames
472  );
473  }
474 
475 
476 
477  // Convert any fields
478 
479  forAll(timeDirs, timeI)
480  {
481  runTime.setTime(timeDirs[timeI], timeI);
482 
483  Info<< "Time: " << runTime.timeName() << endl;
484 
485  // See if mesh in time directory
486  IOobject io
487  (
488  "boundary",
489  runTime.timeName(),
491  runTime,
494  false
495  );
496 
497  if (io.typeHeaderOk<IOPtrList<entry>>(false))
498  {
499  rewriteBoundary
500  (
501  dryrun,
502  io,
503  regionPrefix,
504  thisNames,
505  nbrNames
506  );
507  }
508 
509 
510  IOobjectList objects(runTime, runTime.timeName());
511 
512 
513  const int oldFlag = entry::disableFunctionEntries;
514  if (!enableEntries)
515  {
516  // By default disable dictionary expansion for fields
518  }
519 
520  // volFields
521  // ~~~~~~~~~
522 
523  rewriteFields
524  (
525  dryrun,
526  runTime,
527  objects.names(volScalarField::typeName),
528  thisNames,
529  nbrNames
530  );
531  rewriteFields
532  (
533  dryrun,
534  runTime,
535  objects.names(volVectorField::typeName),
536  thisNames,
537  nbrNames
538  );
539  rewriteFields
540  (
541  dryrun,
542  runTime,
543  objects.names(volSphericalTensorField::typeName),
544  thisNames,
545  nbrNames
546  );
547  rewriteFields
548  (
549  dryrun,
550  runTime,
551  objects.names(volSymmTensorField::typeName),
552  thisNames,
553  nbrNames
554  );
555  rewriteFields
556  (
557  dryrun,
558  runTime,
559  objects.names(volTensorField::typeName),
560  thisNames,
561  nbrNames
562  );
563 
564 
565  // pointFields
566  // ~~~~~~~~~~~
567 
568  rewriteFields
569  (
570  dryrun,
571  runTime,
572  objects.names(pointScalarField::typeName),
573  thisNames,
574  nbrNames
575  );
576  rewriteFields
577  (
578  dryrun,
579  runTime,
580  objects.names(pointVectorField::typeName),
581  thisNames,
582  nbrNames
583  );
584  rewriteFields
585  (
586  dryrun,
587  runTime,
588  objects.names(pointSphericalTensorField::typeName),
589  thisNames,
590  nbrNames
591  );
592  rewriteFields
593  (
594  dryrun,
595  runTime,
596  objects.names(pointSymmTensorField::typeName),
597  thisNames,
598  nbrNames
599  );
600  rewriteFields
601  (
602  dryrun,
603  runTime,
604  objects.names(pointTensorField::typeName),
605  thisNames,
606  nbrNames
607  );
608 
609 
610  // surfaceFields
611  // ~~~~~~~~~~~
612 
613  rewriteFields
614  (
615  dryrun,
616  runTime,
617  objects.names(surfaceScalarField::typeName),
618  thisNames,
619  nbrNames
620  );
621  rewriteFields
622  (
623  dryrun,
624  runTime,
625  objects.names(surfaceVectorField::typeName),
626  thisNames,
627  nbrNames
628  );
629  rewriteFields
630  (
631  dryrun,
632  runTime,
633  objects.names(surfaceSphericalTensorField::typeName),
634  thisNames,
635  nbrNames
636  );
637  rewriteFields
638  (
639  dryrun,
640  runTime,
641  objects.names(surfaceSymmTensorField::typeName),
642  thisNames,
643  nbrNames
644  );
645  rewriteFields
646  (
647  dryrun,
648  runTime,
649  objects.names(surfaceTensorField::typeName),
650  thisNames,
651  nbrNames
652  );
653 
655  }
656 
657  return 0;
658 }
659 
660 
661 // ************************************************************************* //
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
volFields.H
Foam::IOdictionary
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:54
runTime
engineTime & runTime
Definition: createEngineTime.H:13
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:104
Foam::dictionaryEntry
A keyword and a list of tokens is a 'dictionaryEntry'.
Definition: dictionaryEntry.H:65
Foam::dictionary::changeKeyword
bool changeKeyword(const keyType &oldKeyword, const keyType &newKeyword, bool overwrite=false)
Change the keyword for an entry,.
Definition: dictionarySearch.C:611
Foam::Time
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:73
Foam::IOobject::timeStamp
Definition: IOobject.H:136
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::IOPtrList
A PtrList of objects of type <T> with automated input and output.
Definition: IOPtrList.H:53
Foam::polyMesh::defaultRegion
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:312
cyclicPolyPatch.H
Foam::argList::getOrDefault
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:286
Foam::dictionary::found
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Search for an entry (const access) with the given keyword.
Definition: dictionary.C:364
Foam::IOobject::typeHeaderOk
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.
Definition: IOobjectTemplates.C:39
Foam::polyMesh::meshSubDir
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:315
Foam::polyBoundaryMesh::reorder
void reorder(const labelUList &oldToNew, const bool validBoundary)
Reorders patches. Ordering does not have to be done in.
Definition: polyBoundaryMesh.C:1192
Foam::Time::timeName
static word timeName(const scalar t, const int precision=precision_)
Definition: Time.C:785
Foam::IOobject::fileModificationChecking
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:211
Foam::argList::addNote
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:413
Foam::HashTable::insert
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:168
Foam::argList::addOptionCompat
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:369
string.H
IOobjectList.H
Foam::defineTemplateTypeNameAndDebug
defineTemplateTypeNameAndDebug(faScalarMatrix, 0)
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
surfaceFields.H
Foam::surfaceFields.
Foam::dictionary::get
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:81
Foam::dictionary::set
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:847
polyMesh.H
entry.H
Foam::sumOp
Definition: ops.H:213
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::dictionary::null
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition: dictionary.H:385
regionName
Foam::word regionName
Definition: createNamedDynamicFvMesh.H:1
Foam::regIOobject::write
virtual bool write(const bool valid=true) const
Write using setting from DB.
Definition: regIOobjectWrite.C:165
IOPtrList.H
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
argList.H
Foam::dictionary::subDict
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:528
addRegionOption.H
Foam::PtrList::setSize
void setSize(const label newLen)
Same as resize()
Definition: PtrListI.H:108
Foam::PtrList< entry >
size_type
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:76
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::entry::disableFunctionEntries
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:119
Foam::PtrList::set
const T * set(const label i) const
Return const pointer to element (if set) or nullptr.
Definition: PtrListI.H:143
dictionaryEntry.H
Foam::IOobjectList
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:55
Foam::IOobject::headerClassName
const word & headerClassName() const
Return name of the class name read from header.
Definition: IOobjectI.H:88
Foam::HashTable
A HashTable similar to std::unordered_map.
Definition: HashTable.H:105
Foam::mvBak
bool mvBak(const fileName &src, const std::string &ext="bak")
Rename to a corresponding backup file.
Definition: MSwindows.C:958
Foam::argList::addBoolOption
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:325
IOdictionary.H
Time.H
setRootCase.H
Foam::nl
constexpr char nl
Definition: Ostream.H:385
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
Foam::objectRegistry::names
wordList names() const
The names of all objects.
Definition: objectRegistry.C:164
Foam::timeSelector::addOptions
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:108
Foam::dictionary::remove
bool remove(const word &keyword)
Remove an entry specified by keyword.
Definition: dictionarySearch.C:582
Foam::List< label >
Foam::Time::setTime
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:1006
Foam::word::null
static const word null
An empty word.
Definition: word.H:77
timeSelector.H
createTime.H
Foam::IOobject::MUST_READ_IF_MODIFIED
Definition: IOobject.H:121
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::dictionary::add
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:708
Foam::keyType::LITERAL
String literal.
Definition: keyType.H:73
Foam::IOobject::objectPath
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:209
Foam::timeSelector::select0
static instantList select0(Time &runTime, const argList &args)
Definition: timeSelector.C:241
Foam::TimePaths::constant
const word & constant() const
Return constant name.
Definition: TimePathsI.H:88
args
Foam::argList args(argc, argv)
pointFields.H
Foam::argList::found
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:157
Foam::IOobject::MUST_READ
Definition: IOobject.H:120