Loading...
Searching...
No Matches
changeDictionary.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) 2016-2022 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 changeDictionary
29
30Group
31 grpPreProcessingUtilities
32
33Description
34 Utility to change dictionary entries, e.g. can be used to change the patch
35 type in the field and polyMesh/boundary files.
36
37 Reads dictionaries (fields) and entries to change from a dictionary.
38 E.g. to make the \em movingWall a \em fixedValue for \em p but all other
39 \em Walls a zeroGradient boundary condition, the
40 \c system/changeDictionaryDict would contain the following:
41 \verbatim
42 p // field to change
43 {
44 boundaryField
45 {
46 ".*Wall" // entry to change
47 {
48 type zeroGradient;
49 }
50 movingWall // entry to change
51 {
52 type fixedValue;
53 value uniform 123.45;
54 }
55 }
56 }
57 \endverbatim
58 Replacement entries starting with '~' will remove the entry.
59
60Usage
61 \b changeDictionary [OPTION]
62
63 Options:
64 - \par -subDict
65 Specify the subDict name of the replacements dictionary.
66
67 - \par -literalRE
68 Do not interpret regular expressions or patchGroups; treat them as any
69 other keyword.
70
71 - \par -enableFunctionEntries
72 Enable function entries (default: disabled)
73
74 - \par -disablePatchGroups
75 Disable the default checking for keys being patchGroups
76
77\*---------------------------------------------------------------------------*/
78
79#include "argList.H"
80#include "IOobjectList.H"
81#include "IOPtrList.H"
82#include "volFields.H"
83#include "timeSelector.H"
84
85using namespace Foam;
86
87// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
88
89namespace Foam
90{
92}
93
94
95// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
96
97// Extract groupPatch info from boundary file info
98HashTable<wordList> extractPatchGroups(const dictionary& boundaryDict)
99{
100 HashTable<wordList> groupToPatch;
101
102 for (const entry& dEntry : boundaryDict)
103 {
104 if (!dEntry.isDict())
105 {
106 continue;
107 }
108
109 const word& patchName = dEntry.keyword();
110 const dictionary& patchDict = dEntry.dict();
111
112 wordList groupNames;
113 patchDict.readIfPresent("inGroups", groupNames);
114
115 for (const word& groupName : groupNames)
116 {
117 auto groupIter = groupToPatch.find(groupName);
118 if (groupIter.good())
119 {
120 (*groupIter).append(patchName);
121 }
122 else
123 {
124 groupToPatch.insert(groupName, wordList(one{}, patchName));
125 }
126 }
127 }
128
129 return groupToPatch;
130}
131
132
133bool merge
134(
135 const bool addNonExisting,
136 dictionary&,
137 const dictionary&,
138 const bool,
140);
141
142
143// Add thisEntry to dictionary thisDict.
144bool addEntry
145(
146 dictionary& thisDict,
147 entry& thisEntry,
148 const entry& mergeEntry,
149 const bool literalRE,
150 const HashTable<wordList>& shortcuts
151)
152{
153 bool changed = false;
154
155 // Recursively merge sub-dictionaries
156 // TODO: merge without copying
157 if (thisEntry.isDict() && mergeEntry.isDict())
158 {
159 if
160 (
161 merge
162 (
163 true,
164 const_cast<dictionary&>(thisEntry.dict()),
165 mergeEntry.dict(),
166 literalRE,
167 shortcuts
168 )
169 )
170 {
171 changed = true;
172 }
173 }
174 else
175 {
176 // Should use in-place modification instead of adding
177 thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
178 changed = true;
179 }
180
181 return changed;
182}
183
184
185// List of indices into thisKeys
186labelList findMatches
187(
188 const HashTable<wordList>& shortcuts,
189 const wordList& shortcutNames,
190 const wordList& thisKeys,
191 const wordRe& key
192)
193{
194 labelList matches;
195
196 if (key.isPattern())
197 {
198 // Wildcard match
199 matches = wordRes::matching(key, thisKeys);
200 }
201 else if (shortcuts.size())
202 {
203 // See if patchGroups expand to valid thisKeys
204 labelList indices = wordRes::matching(key, shortcutNames);
205
206 for (const label idx : indices)
207 {
208 const word& name = shortcutNames[idx];
209 const wordList& keys = shortcuts[name];
210 for (const word& k : keys)
211 {
212 const label index = thisKeys.find(k);
213 if (index != -1)
214 {
215 matches.append(index);
216 }
217 }
218 }
219 }
220 return matches;
221}
222
223
224// Dictionary merging/editing.
225// literalRE:
226// - true: behave like dictionary::merge, i.e. add regexps just like
227// any other key.
228// - false : interpret wildcard as a rule for items to be matched.
229bool merge
230(
231 const bool addNonExisting,
232 dictionary& thisDict,
233 const dictionary& mergeDict,
234 const bool literalRE,
235 const HashTable<wordList>& shortcuts
236)
237{
238 const wordList shortcutNames(shortcuts.toc());
239
240 bool changed = false;
241
242 // Save current (non-wildcard) keys before adding items.
243 wordHashSet thisKeysSet;
244 {
245 for (const word& k : thisDict.keys(false))
246 {
247 thisKeysSet.insert(k);
248 }
249 }
250
251 // Pass 1. All literal matches
252
253 for (const entry& mergeEntry : mergeDict)
254 {
255 const keyType& key = mergeEntry.keyword();
256
257 if (key[0] == '~')
258 {
259 const word eraseKey = key.substr(1);
260 if (thisDict.remove(eraseKey))
261 {
262 // Mark thisDict entry as having been match for wildcard
263 // handling later on.
264 thisKeysSet.erase(eraseKey);
265 }
266 changed = true;
267 }
268 else if (literalRE || !(key.isPattern() || shortcuts.found(key)))
269 {
270 entry* eptr = thisDict.findEntry(key, keyType::LITERAL);
271
272 if (eptr)
273 {
274 // Mark thisDict entry as having been match for wildcard
275 // handling later on.
276 thisKeysSet.erase(eptr->keyword());
277
278 if
279 (
280 addEntry
281 (
282 thisDict,
283 *eptr,
284 mergeEntry,
285 literalRE,
286 shortcuts
287 )
288 )
289 {
290 changed = true;
291 }
292 }
293 else
294 {
295 if (addNonExisting)
296 {
297 // Not found - just add
298 thisDict.add(mergeEntry.clone(thisDict).ptr());
299 changed = true;
300 }
301 else
302 {
303 IOWarningInFunction(mergeDict)
304 << "Ignoring non-existing entry " << key
305 << endl;
306 }
307 }
308 }
309 }
310
311
312 // Pass 2. Wildcard or shortcut matches (if any) on any non-match keys.
313
314 if (!literalRE && thisKeysSet.size())
315 {
316 // Pick up remaining dictionary entries
317 wordList thisKeys(thisKeysSet.toc());
318
319 for (const entry& mergeEntry : mergeDict)
320 {
321 const keyType& key = mergeEntry.keyword();
322
323 if (key[0] == '~')
324 {
325 const word eraseKey = key.substr(1);
326
327 // List of indices into thisKeys
328 labelList matches
329 (
330 findMatches
331 (
332 shortcuts,
333 shortcutNames,
334 thisKeys,
335 eraseKey
336 )
337 );
338
339 // Remove all matches
340 for (const label matchi : matches)
341 {
342 const word& k = thisKeys[matchi];
343 thisKeysSet.erase(k);
344 }
345 changed = true;
346 }
347 else
348 {
349 // List of indices into thisKeys
350 labelList matches
351 (
352 findMatches
353 (
354 shortcuts,
355 shortcutNames,
356 thisKeys,
357 key
358 )
359 );
360
361 // Add all matches
362 for (const label matchi : matches)
363 {
364 const word& k = thisKeys[matchi];
365
366 entry* eptr = thisDict.findEntry(k, keyType::LITERAL);
367
368 if
369 (
370 addEntry
371 (
372 thisDict,
373 *eptr,
374 mergeEntry,
375 literalRE,
376 HashTable<wordList>(0) // no shortcuts
377 // at deeper levels
378 )
379 )
380 {
381 changed = true;
382 }
383 }
384 }
385 }
386 }
387
388 return changed;
389}
390
391
392
393int main(int argc, char *argv[])
394{
396 (
397 "Utility to change dictionary entries"
398 " (such as the patch type for fields and polyMesh/boundary files)."
399 );
400
401 argList::addOption("dict", "file", "Alternative changeDictionaryDict");
402
404 (
405 "subDict",
406 "name",
407 "Specify the subDict name of the replacements dictionary"
408 );
410 (
411 "instance",
412 "name",
413 "Override instance setting (default is the time name)"
414 );
415
416 // Add explicit time option
418
420 (
421 "literalRE",
422 "Treat regular expressions literally (i.e., as a keyword)"
423 );
425 (
426 "enableFunctionEntries",
427 "Enable expansion of dictionary directives - #include, #codeStream etc"
428 );
430 (
431 "disablePatchGroups",
432 "Disable matching keys to patch groups"
433 );
434
435 #include "addRegionOption.H"
436
437 #include "setRootCase.H"
438 #include "createTime.H"
439
440 // Optionally override controlDict time with -time options
442 if (times.size() < 1)
443 {
445 << "No times selected." << exit(FatalError);
446 }
447 forAll(times, timei)
448 {
449 word instance;
450 if (args.readIfPresent("instance", instance))
451 {
452 if (times.size() > 1)
453 {
455 << "Multiple times selected with 'instance' option"
456 << exit(FatalError);
457 }
458 }
459 else
460 {
461 runTime.setTime(times[timei], timei);
462 instance = runTime.timeName();
463 }
464
465 #include "createNamedMesh.H"
466
467 const bool literalRE = args.found("literalRE");
468 if (literalRE)
469 {
470 Info<< "Not interpreting any regular expressions (RE)"
471 << " in the changeDictionaryDict." << endl
472 << "Instead they are handled as any other entry, i.e. added if"
473 << " not present." << endl;
474 }
475
476 const bool enableEntries = args.found("enableFunctionEntries");
477 if (enableEntries)
478 {
479 Info<< "Allowing dictionary preprocessing (#include, #codeStream)."
480 << endl;
481 }
482
483 const int oldFlag = entry::disableFunctionEntries;
484 if (!enableEntries)
485 {
486 // By default disable dictionary expansion for fields
488 }
489
490
491 const bool disablePatchGroups = args.found("disablePatchGroups");
492 if (disablePatchGroups)
493 {
494 Info<< "Not interpreting any keys in the changeDictionary"
495 << " as patchGroups"
496 << endl;
497 }
498
499
500 // Make sure we do not use the master-only reading since we read
501 // fields (different per processor) as dictionaries.
503
504
505 // Get the replacement rules from a dictionary
506
507 const word dictName("changeDictionaryDict");
510
511 const dictionary* replaceDictsPtr = &dict;
512
513 if (args.found("subDict"))
514 {
515 replaceDictsPtr = &dict.subDict(args["subDict"]);
516 }
517
518 const dictionary& replaceDicts = *replaceDictsPtr;
519
520 Info<< "Read dictionary " << dict.name()
521 << " with replacements for dictionaries "
522 << replaceDicts.toc() << endl;
523
524
525
526 // Always read boundary to get patch groups
527 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
528
529 Info<< "Reading polyMesh/boundary file to extract patch names"
530 << endl;
531
532 // Read PtrList of dictionary as dictionary.
533 const word oldTypeName = IOPtrList<entry>::typeName;
535 IOPtrList<entry> dictList
536 (
538 (
539 "boundary",
540 runTime.findInstance
541 (
543 "boundary",
545 ),
547 mesh,
551 )
552 );
553 const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
554
555 // Fake type back to what was in field
556 const_cast<word&>(dictList.type()) = dictList.headerClassName();
557
558 // Temporary convert to dictionary
559 dictionary fieldDict;
560 for (const entry& e : dictList)
561 {
562 if (e.isDict())
563 {
564 fieldDict.add(e.keyword(), e.dict());
565 }
566 }
567
568 if (dictList.size())
569 {
570 Info<< "Loaded dictionary " << dictList.name()
571 << " with entries " << fieldDict.toc() << endl;
572 }
573
574 // Extract any patchGroups information (= shortcut for set of
575 // patches)
576 HashTable<wordList> patchGroups;
577 if (!disablePatchGroups)
578 {
579 patchGroups = extractPatchGroups(fieldDict);
580 if (patchGroups.size())
581 {
582 Info<< "Extracted patch groups:" << endl;
583 wordList groups(patchGroups.sortedToc());
584 forAll(groups, i)
585 {
586 Info<< " group " << groups[i] << " with patches "
587 << patchGroups[groups[i]] << endl;
588 }
589 }
590 }
591
592
593 // Every replacement is a dictionary name and a keyword in this
594
595 for (const entry& replaceEntry : replaceDicts)
596 {
597 if (!replaceEntry.isDict())
598 {
599 // Could also warn
600 continue;
601 }
602
603 const word& fieldName = replaceEntry.keyword();
604 const dictionary& replaceDict = replaceEntry.dict();
605
606 Info<< "Replacing entries in dictionary " << fieldName << endl;
607
608 // Handle 'boundary' specially:
609 // - is PtrList of dictionaries
610 // - is in polyMesh/
611 if (fieldName == "boundary")
612 {
613 Info<< "Special handling of " << fieldName
614 << " as polyMesh/boundary file." << endl;
615
616 // Merge the replacements in. Do not add non-existing entries.
617 Info<< "Merging entries from " << replaceDict.toc() << endl;
618 merge(false, fieldDict, replaceDict, literalRE, patchGroups);
619
620 Info<< "fieldDict:" << fieldDict << endl;
621
622 // Convert back into dictList
623 wordList doneKeys(dictList.size());
624
625 label nEntries = fieldDict.size();
626 nEntries = 0;
627
628 forAll(dictList, i)
629 {
630 doneKeys[i] = dictList[i].keyword();
631
632 const entry* ePtr = fieldDict.findEntry
633 (
634 doneKeys[i],
636 );
637 // Check that it hasn't been removed from fieldDict
638 if (ePtr)
639 {
640 dictList.set(nEntries++, ePtr->clone());
641 fieldDict.remove(doneKeys[i]);
642 }
643 }
644
645 // Add remaining entries
646 for (const entry& e : fieldDict)
647 {
648 dictList.set(nEntries++, e.clone());
649 }
650 dictList.setSize(nEntries);
651
652 Info<< "Writing modified " << fieldName << endl;
653 dictList.writeObject
654 (
655 IOstreamOption(runTime.writeFormat()),
656 true
657 );
658 }
659 else
660 {
661 // Read dictionary
662 // Note: disable class type checking so we can load field
663 Info<< "Loading dictionary " << fieldName << endl;
664 const word oldTypeName = localIOdictionary::typeName;
665 const_cast<word&>(localIOdictionary::typeName) = word::null;
666
667 IOobject fieldHeader
668 (
669 fieldName,
670 instance,
671 mesh,
675 );
676
677 if (fieldHeader.typeHeaderOk<localIOdictionary>(false))
678 {
679 //IOdictionary fieldDict(fieldHeader);
680 //- dictionaries to-be-changed are either boundary
681 // or field dictionary. Both are processor-local.
682 localIOdictionary fieldDict(fieldHeader);
683
684 const_cast<word&>(localIOdictionary::typeName) =
685 oldTypeName;
686
687 // Fake type back to what was in field
688 const_cast<word&>(fieldDict.type()) =
689 fieldDict.headerClassName();
690
691 Info<< "Loaded dictionary " << fieldName
692 << " with entries " << fieldDict.toc() << endl;
693
694 // Merge the replacements in (allow adding)
695 Info<< "Merging entries from " << replaceDict.toc() << endl;
696 merge(true, fieldDict, replaceDict, literalRE, patchGroups);
697
698 Info<< "Writing modified fieldDict " << fieldName << endl;
699 fieldDict.regIOobject::write();
700 }
701 else
702 {
704 << "Requested field to change " << fieldName
705 << " does not exist in " << fieldHeader.path() << endl;
706 }
707 }
708
710 }
711 }
712
713 Info<< "\nEnd\n" << endl;
714
715 return 0;
716}
717
718
719// ************************************************************************* //
label k
Required Classes.
label size() const noexcept
The number of elements in list.
Definition DLListBase.H:194
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
A HashTable similar to std::unordered_map.
Definition HashTable.H:124
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition HashTable.C:156
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition HashTable.C:141
bool found(const Key &key) const
Same as contains().
Definition HashTable.H:1370
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition HashTableI.H:152
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition HashTableI.H:86
label size() const noexcept
The number of elements in table.
Definition HashTable.H:358
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition HashTable.C:489
A PtrList of objects of type <T> with automated input and output.
Definition IOPtrList.H:53
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
@ NO_REGISTER
Do not request registration (bool: false).
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition IOobject.H:358
A simple container for options an IOstream can normally have.
void append(const T &val)
Append an element at the end of the list.
Definition List.H:497
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label find(const T &val) const
Find index of the first occurrence of the value.
Definition UList.C:160
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition argList.C:389
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition argList.C:400
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
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
bool remove(const word &keyword)
Remove an entry specified by keyword.
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition dictionary.C:607
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition dictionary.C:625
wordList toc() const
Return the table of contents.
Definition dictionary.C:587
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
virtual bool isDict() const noexcept
True if this entry is a dictionary.
Definition entry.H:284
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
const keyType & keyword() const noexcept
Return keyword.
Definition entry.H:231
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary, otherwise Fatal.
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition entry.H:139
A class for handling keywords in dictionaries.
Definition keyType.H:69
@ LITERAL
String literal.
Definition keyType.H:82
@ REGEX
Regular expression.
Definition keyType.H:83
localIOdictionary is derived from IOdictionary but excludes parallel master reading.
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition one.H:57
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir).
Definition polyMesh.C:826
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh").
Definition polyMesh.H:411
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
static instantList selectIfPresent(Time &runTime, const argList &args)
If any time option provided return the set of times - as per select0() - otherwise return just the cu...
A wordRe is a Foam::word, but can contain a regular expression for matching words or strings.
Definition wordRe.H:81
static labelList matching(const wordRe &select, const UList< StringType > &input, const bool invert=false)
Determine the list indices for all matches.
A class for handling words, derived from Foam::string.
Definition word.H:66
static const word null
An empty word.
Definition word.H:84
#define defineTemplateTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information for templates, useful.
Definition className.H:158
dynamicFvMesh & mesh
engineTime & runTime
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
Required Classes.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const word dictName("faMeshDefinition")
auto & name
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
#define WarningInFunction
Report a warning using Foam::Warning.
constexpr auto key(const Type &t) noexcept
Helper function to return the enum value.
Namespace for OpenFOAM.
List< word > wordList
List of word.
Definition fileName.H:60
HashSet< word, Hash< word > > wordHashSet
A HashSet of words, uses string hasher.
Definition HashSet.H:80
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< instant > instantList
List of instants.
Definition instantList.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
dictionary dict
IOobject dictIO
Foam::argList args(argc, argv)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299