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-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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
27Application
28 foamUpgradeCyclics
29
30Group
31 grpPreProcessingUtilities
32
33Description
34 Tool to upgrade mesh and fields for split cyclics.
35
36Usage
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
63using namespace Foam;
64
65// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
66
67namespace Foam
68{
70}
71
72
73// Read boundary file without reading mesh
74void 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,
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
267void 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 (
285 (
286 fieldName,
287 runTime.timeName(),
288 runTime,
289 IOobject::MUST_READ_IF_MODIFIED,
290 IOobject::NO_WRITE,
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
373void 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
397int main(int argc, char *argv[])
398{
399 argList::addNote
400 (
401 "Tool to upgrade mesh and fields for split cyclics"
402 );
403
404 timeSelector::addOptions();
405
406 argList::addOptionCompat("dry-run", {"test", 1806});
407 argList::addDryRunOption
408 (
409 "Test only do not change any files"
410 );
411 argList::addBoolOption
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.
424 IOobject::fileModificationChecking = IOobject::timeStamp;
425
426
427 instantList timeDirs = timeSelector::select0(runTime, args);
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 =
437 args.getOrDefault<word>("region", polyMesh::defaultRegion);
438
439 fileName regionPrefix;
440 if (regionName != polyMesh::defaultRegion)
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.
452 (
453 "boundary",
454 runTime.constant(),
455 polyMesh::meshSubDir,
456 runTime,
457 IOobject::MUST_READ,
458 IOobject::NO_WRITE,
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
486 (
487 "boundary",
488 runTime.timeName(),
489 polyMesh::meshSubDir,
490 runTime,
491 IOobject::MUST_READ,
492 IOobject::NO_WRITE,
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
516 entry::disableFunctionEntries = 1;
517 }
518
519 // volFields
520 // ~~~~~~~~~
521
522 rewriteFields
523 (
524 dryrun,
525 runTime,
526 objects.names(volScalarField::typeName),
527 thisNames,
528 nbrNames
529 );
530 rewriteFields
531 (
532 dryrun,
533 runTime,
534 objects.names(volVectorField::typeName),
535 thisNames,
536 nbrNames
537 );
538 rewriteFields
539 (
540 dryrun,
541 runTime,
542 objects.names(volSphericalTensorField::typeName),
543 thisNames,
544 nbrNames
545 );
546 rewriteFields
547 (
548 dryrun,
549 runTime,
550 objects.names(volSymmTensorField::typeName),
551 thisNames,
552 nbrNames
553 );
554 rewriteFields
555 (
556 dryrun,
557 runTime,
558 objects.names(volTensorField::typeName),
559 thisNames,
560 nbrNames
561 );
562
563
564 // pointFields
565 // ~~~~~~~~~~~
566
567 rewriteFields
568 (
569 dryrun,
570 runTime,
571 objects.names(pointScalarField::typeName),
572 thisNames,
573 nbrNames
574 );
575 rewriteFields
576 (
577 dryrun,
578 runTime,
579 objects.names(pointVectorField::typeName),
580 thisNames,
581 nbrNames
582 );
583 rewriteFields
584 (
585 dryrun,
586 runTime,
587 objects.names(pointSphericalTensorField::typeName),
588 thisNames,
589 nbrNames
590 );
591 rewriteFields
592 (
593 dryrun,
594 runTime,
595 objects.names(pointSymmTensorField::typeName),
596 thisNames,
597 nbrNames
598 );
599 rewriteFields
600 (
601 dryrun,
602 runTime,
603 objects.names(pointTensorField::typeName),
604 thisNames,
605 nbrNames
606 );
607
608
609 // surfaceFields
610 // ~~~~~~~~~~~
611
612 rewriteFields
613 (
614 dryrun,
615 runTime,
616 objects.names(surfaceScalarField::typeName),
617 thisNames,
618 nbrNames
619 );
620 rewriteFields
621 (
622 dryrun,
623 runTime,
624 objects.names(surfaceVectorField::typeName),
625 thisNames,
626 nbrNames
627 );
628 rewriteFields
629 (
630 dryrun,
631 runTime,
632 objects.names(surfaceSphericalTensorField::typeName),
633 thisNames,
634 nbrNames
635 );
636 rewriteFields
637 (
638 dryrun,
639 runTime,
640 objects.names(surfaceSymmTensorField::typeName),
641 thisNames,
642 nbrNames
643 );
644 rewriteFields
645 (
646 dryrun,
647 runTime,
648 objects.names(surfaceTensorField::typeName),
649 thisNames,
650 nbrNames
651 );
652
653 entry::disableFunctionEntries = oldFlag;
654 }
655
656 return 0;
657}
658
659
660// ************************************************************************* //
label size_type
The type to represent the size of a buffer.
A HashTable similar to std::unordered_map.
Definition: HashTable.H:123
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:180
A PtrList of objects of type <T> with automated input and output.
Definition: IOPtrList.H:57
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:59
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: PtrList.H:73
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:178
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:307
A keyword and a list of tokens is a 'dictionaryEntry'.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
bool changeKeyword(const keyType &oldKeyword, const keyType &newKeyword, bool overwrite=false)
Change the keyword for an entry,.
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:460
bool remove(const word &keyword)
Remove an entry specified by keyword.
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Search for an entry (const access) with the given keyword.
Definition: dictionaryI.H:87
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:640
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:780
A class for handling file names.
Definition: fileName.H:76
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTemplateTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information for templates, useful.
Definition: className.H:132
const polyBoundaryMesh & patches
engineTime & runTime
Foam::word regionName(Foam::polyMesh::defaultRegion)
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
Namespace for OpenFOAM.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
bool mvBak(const fileName &src, const std::string &ext="bak")
Rename to a corresponding backup file.
Definition: MSwindows.C:976
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition: stdFoam.H:278
Foam::surfaceFields.