foamUpgradeCyclics.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  foamUpgradeCyclics
26 
27 Description
28  Tool to upgrade mesh and fields for split cyclics.
29 
30 Usage
31  \b foamUpgradeCyclics [OPTION]
32 
33  Options:
34  - \par -test
35  Suppress writing the updated files with split cyclics
36 
37  - \par -enableFunctionEntries
38  By default all dictionary preprocessing of fields is disabled
39 
40 \*---------------------------------------------------------------------------*/
41 
42 #include "argList.H"
43 #include "Time.H"
44 #include "timeSelector.H"
45 #include "IOdictionary.H"
46 #include "polyMesh.H"
47 #include "entry.H"
48 #include "IOPtrList.H"
49 #include "cyclicPolyPatch.H"
50 #include "dictionaryEntry.H"
51 #include "IOobjectList.H"
52 #include "volFields.H"
53 #include "pointFields.H"
54 #include "surfaceFields.H"
55 #include "string.H"
56 
57 using namespace Foam;
58 
59 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
60 
61 namespace Foam
62 {
64 }
65 
66 
67 // Read boundary file without reading mesh
68 void rewriteBoundary
69 (
70  const bool isTestRun,
71  const IOobject& io,
72  const fileName& regionPrefix,
73  HashTable<word>& thisNames,
74  HashTable<word>& nbrNames
75 )
76 {
77  Info<< "Reading boundary from " << typeFilePath<IOPtrList<entry>>(io)
78  << endl;
79 
80  // Read PtrList of dictionary.
81  const word oldTypeName = IOPtrList<entry>::typeName;
84  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
85  // Fake type back to what was in field
86  const_cast<word&>(patches.type()) = patches.headerClassName();
87 
88 
89  // Replace any 'cyclic'
90  label nOldCyclics = 0;
92  {
93  const dictionary& patchDict = patches[patchi].dict();
94 
95  if (word(patchDict["type"]) == cyclicPolyPatch::typeName)
96  {
97  if (!patchDict.found("neighbourPatch"))
98  {
99  Info<< "Patch " << patches[patchi].keyword()
100  << " does not have 'neighbourPatch' entry; assuming it"
101  << " is of the old type." << endl;
102  nOldCyclics++;
103  }
104  }
105  }
106 
107  Info<< "Detected " << nOldCyclics << " old cyclics." << nl << endl;
108 
109 
110  // Save old patches.
111  PtrList<entry> oldPatches(patches);
112 
113  // Extend
114  label nOldPatches = patches.size();
115  patches.setSize(nOldPatches+nOldCyclics);
116 
117  // Create reordering map
118  labelList oldToNew(patches.size());
119 
120 
121  // Add new entries
122  label addedPatchi = nOldPatches;
123  label newPatchi = 0;
124  forAll(oldPatches, patchi)
125  {
126  const dictionary& patchDict = oldPatches[patchi].dict();
127 
128  if
129  (
130  word(patchDict["type"]) == cyclicPolyPatch::typeName
131  )
132  {
133  const word& name = oldPatches[patchi].keyword();
134 
135  if (patchDict.found("neighbourPatch"))
136  {
137  patches.set(patchi, oldPatches.set(patchi, nullptr));
138  oldToNew[patchi] = newPatchi++;
139 
140  // Check if patches come from automatic conversion
141  word oldName;
142 
143  string::size_type i = name.rfind("_half0");
144  if (i != string::npos)
145  {
146  oldName = name.substr(0, i);
147  thisNames.insert(oldName, name);
148  Info<< "Detected converted cyclic patch " << name
149  << " ; assuming it originates from " << oldName
150  << endl;
151  }
152  else
153  {
154  i = name.rfind("_half1");
155  if (i != string::npos)
156  {
157  oldName = name.substr(0, i);
158  nbrNames.insert(oldName, name);
159  Info<< "Detected converted cyclic patch " << name
160  << " ; assuming it originates from " << oldName
161  << endl;
162  }
163  }
164  }
165  else
166  {
167  label nFaces = readLabel(patchDict["nFaces"]);
168  label startFace = readLabel(patchDict["startFace"]);
169 
170  Info<< "Detected old style " << word(patchDict["type"])
171  << " patch " << name << " with" << nl
172  << " nFaces : " << nFaces << nl
173  << " startFace : " << startFace << endl;
174 
175  word thisName = name + "_half0";
176  word nbrName = name + "_half1";
177 
178  thisNames.insert(name, thisName);
179  nbrNames.insert(name, nbrName);
180 
181  // Save current dictionary
182  const dictionary patchDict(patches[patchi].dict());
183 
184  // Change entry on this side
185  patches.set(patchi, oldPatches.set(patchi, nullptr));
186  oldToNew[patchi] = newPatchi++;
187  dictionary& thisPatchDict = patches[patchi].dict();
188  thisPatchDict.add("neighbourPatch", nbrName);
189  thisPatchDict.set("nFaces", nFaces/2);
190  patches[patchi].keyword() = thisName;
191 
192  // Add entry on other side
193  patches.set
194  (
195  addedPatchi,
196  new dictionaryEntry
197  (
198  nbrName,
200  patchDict
201  )
202  );
203  oldToNew[addedPatchi] = newPatchi++;
204  dictionary& nbrPatchDict = patches[addedPatchi].dict();
205  nbrPatchDict.set("neighbourPatch", thisName);
206  nbrPatchDict.set("nFaces", nFaces/2);
207  nbrPatchDict.set("startFace", startFace+nFaces/2);
208  patches[addedPatchi].keyword() = nbrName;
209 
210  Info<< "Replaced with patches" << nl
211  << patches[patchi].keyword() << " with" << nl
212  << " nFaces : "
213  << readLabel(thisPatchDict.lookup("nFaces"))
214  << nl
215  << " startFace : "
216  << readLabel(thisPatchDict.lookup("startFace")) << nl
217  << patches[addedPatchi].keyword() << " with" << nl
218  << " nFaces : "
219  << readLabel(nbrPatchDict.lookup("nFaces"))
220  << nl
221  << " startFace : "
222  << readLabel(nbrPatchDict.lookup("startFace"))
223  << nl << endl;
224 
225  addedPatchi++;
226  }
227  }
228  else
229  {
230  patches.set(patchi, oldPatches.set(patchi, nullptr));
231  oldToNew[patchi] = newPatchi++;
232  }
233  }
234 
235  patches.reorder(oldToNew);
236 
237  if (returnReduce(nOldCyclics, sumOp<label>()) > 0)
238  {
239  if (isTestRun)
240  {
241  // Info<< "-test option: no changes made" << nl << endl;
242  }
243  else
244  {
245  if (mvBak(patches.objectPath(), "old"))
246  {
247  Info<< "Backup to "
248  << (patches.objectPath() + ".old") << nl;
249  }
250 
251  Info<< "Write to "
252  << patches.objectPath() << nl << endl;
253  patches.write();
254  }
255  }
256  else
257  {
258  Info<< "No changes made to boundary file." << nl << endl;
259  }
260 }
261 
262 
263 void rewriteField
264 (
265  const bool isTestRun,
266  const Time& runTime,
267  const word& fieldName,
268  const HashTable<word>& thisNames,
269  const HashTable<word>& nbrNames
270 )
271 {
272  // Read dictionary. (disable class type checking so we can load
273  // field)
274  Info<< "Loading field " << fieldName << endl;
275  const word oldTypeName = IOdictionary::typeName;
276  const_cast<word&>(IOdictionary::typeName) = word::null;
277 
278  IOdictionary fieldDict
279  (
280  IOobject
281  (
282  fieldName,
283  runTime.timeName(),
284  runTime,
287  false
288  )
289  );
290  const_cast<word&>(IOdictionary::typeName) = oldTypeName;
291  // Fake type back to what was in field
292  const_cast<word&>(fieldDict.type()) = fieldDict.headerClassName();
293 
294 
295 
296  dictionary& boundaryField = fieldDict.subDict("boundaryField");
297 
298  label nChanged = 0;
299 
300  forAllConstIter(HashTable<word>, thisNames, iter)
301  {
302  const word& patchName = iter.key();
303  const word& newName = iter();
304 
305  Info<< "Looking for entry for patch " << patchName << endl;
306 
307  // Find old patch name either direct or through wildcards
308  // Find new patch name direct only
309 
310  if
311  (
312  boundaryField.found(patchName)
313  && !boundaryField.found(newName, false, false)
314  )
315  {
316  Info<< " Changing entry " << patchName << " to " << newName
317  << endl;
318 
319  dictionary& patchDict = boundaryField.subDict(patchName);
320 
321  if (patchDict.found("value"))
322  {
323  // Remove any value field since wrong size.
324  patchDict.remove("value");
325  }
326 
327 
328  boundaryField.changeKeyword(patchName, newName);
329  boundaryField.add
330  (
331  nbrNames[patchName],
332  patchDict
333  );
334  Info<< " Adding entry " << nbrNames[patchName] << endl;
335 
336  nChanged++;
337  }
338  }
339 
340  // Info<< "New boundaryField:" << boundaryField << endl;
341 
342  if (returnReduce(nChanged, sumOp<label>()) > 0)
343  {
344  if (isTestRun)
345  {
346  // Info<< "-test option: no changes made" << endl;
347  }
348  else
349  {
350  if (mvBak(fieldDict.objectPath(), "old"))
351  {
352  Info<< "Backup to "
353  << (fieldDict.objectPath() + ".old") << nl;
354  }
355 
356  Info<< "Write to "
357  << fieldDict.objectPath() << endl;
358  fieldDict.regIOobject::write();
359  }
360  }
361  else
362  {
363  Info<< "No changes made to field " << fieldName << endl;
364  }
365  Info<< endl;
366 }
367 
368 
369 void rewriteFields
370 (
371  const bool isTestRun,
372  const Time& runTime,
373  const wordList& fieldNames,
374  const HashTable<word>& thisNames,
375  const HashTable<word>& nbrNames
376 )
377 {
378  forAll(fieldNames, i)
379  {
380  rewriteField
381  (
382  isTestRun,
383  runTime,
384  fieldNames[i],
385  thisNames,
386  nbrNames
387  );
388  }
389 }
390 
391 
392 
393 int main(int argc, char *argv[])
394 {
396 
397  argList::addBoolOption("test", "test only; do not change any files");
399  (
400  "enableFunctionEntries",
401  "enable expansion of dictionary directives - #include, #codeStream etc"
402  );
403  #include "addRegionOption.H"
404 
405  #include "setRootCase.H"
406  #include "createTime.H"
407 
408 
409  // Make sure we do not use the master-only reading since we read
410  // fields (different per processor) as dictionaries.
412 
413 
414  instantList timeDirs = timeSelector::select0(runTime, args);
415 
416  const bool isTestRun = args.optionFound("test");
417  if (isTestRun)
418  {
419  Info<< "-test option: no changes made" << nl << endl;
420  }
421  const bool enableEntries = args.optionFound("enableFunctionEntries");
422 
423 
424  Foam::word regionName = polyMesh::defaultRegion;
425  args.optionReadIfPresent("region", regionName);
426 
427  fileName regionPrefix = "";
428  if (regionName != polyMesh::defaultRegion)
429  {
430  regionPrefix = regionName;
431  }
432 
433 
434  // Per cyclic patch the new name for this side and the other side
435  HashTable<word> thisNames;
436  HashTable<word> nbrNames;
437 
438  // Rewrite constant boundary file. Return any patches that have been split.
439  IOobject io
440  (
441  "boundary",
442  runTime.constant(),
444  runTime,
447  false
448  );
449 
450  if (io.typeHeaderOk<IOPtrList<entry>>(false))
451  {
452  rewriteBoundary
453  (
454  isTestRun,
455  io,
456  regionPrefix,
457  thisNames,
458  nbrNames
459  );
460  }
461 
462 
463 
464  // Convert any fields
465 
466  forAll(timeDirs, timeI)
467  {
468  runTime.setTime(timeDirs[timeI], timeI);
469 
470  Info<< "Time: " << runTime.timeName() << endl;
471 
472  // See if mesh in time directory
473  IOobject io
474  (
475  "boundary",
476  runTime.timeName(),
478  runTime,
481  false
482  );
483 
484  if (io.typeHeaderOk<IOPtrList<entry>>(false))
485  {
486  rewriteBoundary
487  (
488  isTestRun,
489  io,
490  regionPrefix,
491  thisNames,
492  nbrNames
493  );
494  }
495 
496 
497  IOobjectList objects(runTime, runTime.timeName());
498 
499 
500  int oldFlag = entry::disableFunctionEntries;
501  if (!enableEntries)
502  {
503  // By default disable dictionary expansion for fields
505  }
506 
507  // volFields
508  // ~~~~~~~~~
509 
510  rewriteFields
511  (
512  isTestRun,
513  runTime,
514  objects.names(volScalarField::typeName),
515  thisNames,
516  nbrNames
517  );
518  rewriteFields
519  (
520  isTestRun,
521  runTime,
522  objects.names(volVectorField::typeName),
523  thisNames,
524  nbrNames
525  );
526  rewriteFields
527  (
528  isTestRun,
529  runTime,
530  objects.names(volSphericalTensorField::typeName),
531  thisNames,
532  nbrNames
533  );
534  rewriteFields
535  (
536  isTestRun,
537  runTime,
538  objects.names(volSymmTensorField::typeName),
539  thisNames,
540  nbrNames
541  );
542  rewriteFields
543  (
544  isTestRun,
545  runTime,
546  objects.names(volTensorField::typeName),
547  thisNames,
548  nbrNames
549  );
550 
551 
552  // pointFields
553  // ~~~~~~~~~~~
554 
555  rewriteFields
556  (
557  isTestRun,
558  runTime,
559  objects.names(pointScalarField::typeName),
560  thisNames,
561  nbrNames
562  );
563  rewriteFields
564  (
565  isTestRun,
566  runTime,
567  objects.names(pointVectorField::typeName),
568  thisNames,
569  nbrNames
570  );
571  rewriteFields
572  (
573  isTestRun,
574  runTime,
576  thisNames,
577  nbrNames
578  );
579  rewriteFields
580  (
581  isTestRun,
582  runTime,
583  objects.names(pointSymmTensorField::typeName),
584  thisNames,
585  nbrNames
586  );
587  rewriteFields
588  (
589  isTestRun,
590  runTime,
591  objects.names(pointTensorField::typeName),
592  thisNames,
593  nbrNames
594  );
595 
596 
597  // surfaceFields
598  // ~~~~~~~~~~~
599 
600  rewriteFields
601  (
602  isTestRun,
603  runTime,
604  objects.names(surfaceScalarField::typeName),
605  thisNames,
606  nbrNames
607  );
608  rewriteFields
609  (
610  isTestRun,
611  runTime,
612  objects.names(surfaceVectorField::typeName),
613  thisNames,
614  nbrNames
615  );
616  rewriteFields
617  (
618  isTestRun,
619  runTime,
621  thisNames,
622  nbrNames
623  );
624  rewriteFields
625  (
626  isTestRun,
627  runTime,
628  objects.names(surfaceSymmTensorField::typeName),
629  thisNames,
630  nbrNames
631  );
632  rewriteFields
633  (
634  isTestRun,
635  runTime,
636  objects.names(surfaceTensorField::typeName),
637  thisNames,
638  nbrNames
639  );
640 
642  }
643 
644  return 0;
645 }
646 
647 
648 // ************************************************************************* //
Foam::surfaceFields.
dictionary dict
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:431
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
bool remove(const word &)
Remove an entry specified by keyword.
Definition: dictionary.C:966
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
bool typeHeaderOk(const bool checkType=true)
Read header (uses typeFilePath to find file) and check header.
A class for handling file names.
Definition: fileName.H:69
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:50
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:137
static const char *const typeName
Definition: Field.H:94
Foam::word regionName
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:312
static const dictionary null
Null dictionary.
Definition: dictionary.H:202
engineTime & runTime
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:108
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Definition: Time.C:626
patches[0]
A keyword and a list of tokens is a &#39;dictionaryEntry&#39;.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
bool mvBak(const fileName &, const std::string &ext="bak")
Rename to a corresponding backup file.
Definition: POSIX.C:966
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:198
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:814
static List< word > fieldNames
Definition: globalFoam.H:46
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:52
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:692
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
bool changeKeyword(const keyType &oldKeyword, const keyType &newKeyword, bool forceOverwrite=false)
Change the keyword for an entry,.
Definition: dictionary.C:999
static int disableFunctionEntries
Definition: entry.H:86
A class for handling words, derived from string.
Definition: word.H:59
const word & constant() const
Return constant name.
Definition: TimePaths.H:124
static const word null
An empty word.
Definition: word.H:77
An STL-conforming hash table.
Definition: HashTable.H:62
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
label readLabel(Istream &is)
Definition: label.H:64
defineTemplateTypeNameAndDebug(IOPtrList< ensightPart >, 0)
static const char nl
Definition: Ostream.H:265
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:214
static instantList select0(Time &runTime, const argList &args)
Return the set of times selected based on the argList options.
Definition: timeSelector.C:257
A PtrList of objects of type <T> with automated input and output.
Definition: IOPtrList.H:50
label patchi
void set(entry *)
Assign a new entry, overwrite any existing entry.
Definition: dictionary.C:941
messageStream Info
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:110
Foam::argList args(argc, argv)
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
static void addOptions(const bool constant=true, const bool withZero=false)
Add the options handled by timeSelector to argList::validOptions.
Definition: timeSelector.C:114
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:576