changeDictionary.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-2022 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  changeDictionary
26 
27 Description
28  Utility to change dictionary entries, e.g. can be used to change the patch
29  type in the field and polyMesh/boundary files.
30 
31  Reads dictionaries (fields) and entries to change from a dictionary.
32  E.g. to make the \em movingWall a \em fixedValue for \em p but all other
33  \em Walls a zeroGradient boundary condition, the
34  \c system/changeDictionaryDict would contain the following:
35  \verbatim
36  p // field to change
37  {
38  boundaryField
39  {
40  ".*Wall" // entry to change
41  {
42  type zeroGradient;
43  }
44  movingWall // entry to change
45  {
46  type fixedValue;
47  value uniform 123.45;
48  }
49  }
50  }
51  \endverbatim
52  Replacement entries starting with '~' will remove the entry.
53 
54 Usage
55  \b changeDictionary [OPTION]
56 
57  Options:
58  - \par -subDict
59  Specify the subDict name of the replacements dictionary.
60 
61  - \par -literalRE
62  Do not interpret regular expressions or patchGroups; treat them as any
63  other keyword.
64 
65  - \par -enableFunctionEntries
66  Enable function entries (default: disabled)
67 
68  - \par -disablePatchGroups
69  Disable the default checking for keys being patchGroups
70 
71  Note:
72  changeDictionary has been superseded by foamDictionary
73  and is now deprecated.
74 
75 \*---------------------------------------------------------------------------*/
76 
77 #include "argList.H"
78 #include "IOobjectList.H"
79 #include "IOPtrList.H"
80 #include "volFields.H"
81 #include "stringListOps.H"
82 #include "timeSelector.H"
83 #include "systemDict.H"
84 
85 using namespace Foam;
86 
87 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
88 
89 namespace Foam
90 {
92 }
93 
94 
95 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
96 
97 // Extract groupPatch info from boundary file info
98 HashTable<wordList, word> extractPatchGroups(const dictionary& boundaryDict)
99 {
100  HashTable<wordList, word> groupToPatch;
101 
102  forAllConstIter(dictionary, boundaryDict, iter)
103  {
104  const word& patchName = iter().keyword();
105  const dictionary& patchDict = iter().dict();
106 
107  wordList groups;
108  if (patchDict.readIfPresent("inGroups", groups))
109  {
110  forAll(groups, i)
111  {
112  HashTable<wordList, word>::iterator fndGroup = groupToPatch.find
113  (
114  groups[i]
115  );
116  if (fndGroup == groupToPatch.end())
117  {
118  groupToPatch.insert(groups[i], wordList(1, patchName));
119  }
120  else
121  {
122  fndGroup().append(patchName);
123  }
124  }
125  }
126  }
127  return groupToPatch;
128 }
129 
130 
131 bool merge
132 (
133  dictionary&,
134  const dictionary&,
135  const bool,
137 );
138 
139 
140 // Add thisEntry to dictionary thisDict.
141 bool addEntry
142 (
143  dictionary& thisDict,
144  entry& thisEntry,
145  const entry& mergeEntry,
146  const bool literalRE,
147  const HashTable<wordList, word>& shortcuts
148 )
149 {
150  bool changed = false;
151 
152  // Recursively merge sub-dictionaries
153  // TODO: merge without copying
154  if (thisEntry.isDict() && mergeEntry.isDict())
155  {
156  if
157  (
158  merge
159  (
160  const_cast<dictionary&>(thisEntry.dict()),
161  mergeEntry.dict(),
162  literalRE,
163  shortcuts
164  )
165  )
166  {
167  changed = true;
168  }
169  }
170  else
171  {
172  // Should use in-place modification instead of adding
173  thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
174  changed = true;
175  }
176 
177  return changed;
178 }
179 
180 
181 
182 // List of indices into thisKeys
183 labelList findMatches
184 (
185  const HashTable<wordList, word>& shortcuts,
186  const wordList& shortcutNames,
187  const wordList& thisKeys,
188  const keyType& key
189 )
190 {
191  labelList matches;
192 
193  if (key.isPattern())
194  {
195  // Wildcard match
196  matches = findStrings(key, thisKeys);
197 
198  }
199  else if (shortcuts.size())
200  {
201  // See if patchGroups expand to valid thisKeys
202  labelList indices = findStrings(key, shortcutNames);
203  forAll(indices, i)
204  {
205  const word& name = shortcutNames[indices[i]];
206  const wordList& keys = shortcuts[name];
207  forAll(keys, j)
208  {
209  label index = findIndex(thisKeys, keys[j]);
210  if (index != -1)
211  {
212  matches.append(index);
213  }
214  }
215  }
216  }
217  return matches;
218 }
219 
220 
221 // Dictionary merging/editing.
222 // literalRE:
223 // - true: behave like dictionary::merge, i.e. add regexps just like
224 // any other key.
225 // - false : interpret wildcard as a rule for items to be matched.
226 bool merge
227 (
228  dictionary& thisDict,
229  const dictionary& mergeDict,
230  const bool literalRE,
231  const HashTable<wordList, word>& shortcuts
232 )
233 {
234  const wordList shortcutNames(shortcuts.toc());
235 
236  bool changed = false;
237 
238  // Save current (non-wildcard) keys before adding items.
239  HashSet<word> thisKeysSet;
240  {
241  List<keyType> keys = thisDict.keys(false);
242  forAll(keys, i)
243  {
244  thisKeysSet.insert(keys[i]);
245  }
246  }
247 
248  // Pass 1. All literal matches
249 
250  forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
251  {
252  const keyType& key = mergeIter().keyword();
253 
254  if (key[0] == '~')
255  {
256  word eraseKey = key(1, key.size()-1);
257  if (thisDict.remove(eraseKey))
258  {
259  // Mark thisDict entry as having been match for wildcard
260  // handling later on.
261  thisKeysSet.erase(eraseKey);
262  }
263  changed = true;
264  }
265  else if (literalRE || !(key.isPattern() || shortcuts.found(key)))
266  {
267  entry* entryPtr = thisDict.lookupEntryPtr
268  (
269  key,
270  false, // recursive
271  false // patternMatch
272  );
273 
274  if (entryPtr)
275  {
276  // Mark thisDict entry as having been match for wildcard
277  // handling later on.
278  thisKeysSet.erase(entryPtr->keyword());
279 
280  if
281  (
282  addEntry
283  (
284  thisDict,
285  *entryPtr,
286  mergeIter(),
287  literalRE,
288  shortcuts
289  )
290  )
291  {
292  changed = true;
293  }
294  }
295  else
296  {
297  // not found - just add
298  thisDict.add(mergeIter().clone(thisDict).ptr());
299  changed = true;
300  }
301  }
302  }
303 
304 
305  // Pass 2. Wildcard or shortcut matches (if any) on any non-match keys.
306 
307  if (!literalRE && thisKeysSet.size() > 0)
308  {
309  // Pick up remaining dictionary entries
310  wordList thisKeys(thisKeysSet.toc());
311 
312  forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
313  {
314  const keyType& key = mergeIter().keyword();
315 
316  if (key[0] == '~')
317  {
318  word eraseKey = key(1, key.size()-1);
319 
320  // List of indices into thisKeys
321  labelList matches
322  (
323  findMatches
324  (
325  shortcuts,
326  shortcutNames,
327  thisKeys,
328  eraseKey
329  )
330  );
331 
332  // Remove all matches
333  forAll(matches, i)
334  {
335  const word& thisKey = thisKeys[matches[i]];
336  thisKeysSet.erase(thisKey);
337  }
338  changed = true;
339  }
340  else
341  {
342  // List of indices into thisKeys
343  labelList matches
344  (
345  findMatches
346  (
347  shortcuts,
348  shortcutNames,
349  thisKeys,
350  key
351  )
352  );
353 
354  // Add all matches
355  forAll(matches, i)
356  {
357  const word& thisKey = thisKeys[matches[i]];
358 
359  entry& thisEntry = const_cast<entry&>
360  (
361  thisDict.lookupEntry(thisKey, false, false)
362  );
363 
364  if
365  (
366  addEntry
367  (
368  thisDict,
369  thisEntry,
370  mergeIter(),
371  literalRE,
372  HashTable<wordList, word>(0) // no shortcuts
373  // at deeper levels
374  )
375  )
376  {
377  changed = true;
378  }
379  }
380  }
381  }
382  }
383 
384  return changed;
385 }
386 
387 
388 
389 int main(int argc, char *argv[])
390 {
391  #include "addDictOption.H"
393  (
394  "subDict",
395  "name",
396  "specify the subDict name of the replacements dictionary"
397  );
399  (
400  "instance",
401  "name",
402  "override instance setting (default is the time name)"
403  );
404 
405  // Add explicit time option
407 
409  (
410  "literalRE",
411  "treat regular expressions literally (i.e., as a keyword)"
412  );
414  (
415  "enableFunctionEntries",
416  "enable expansion of dictionary directives - #include, #codeStream etc"
417  );
419  (
420  "disablePatchGroups",
421  "disable matching keys to patch groups"
422  );
423 
424  #include "addRegionOption.H"
425 
426  #include "setRootCase.H"
427 
428  Warning
429  << nl
430  << "changeDictionary has been superseded by foamDictionary"
431  " and is now deprecated."
432  << nl << endl;
433 
434  #include "createTime.H"
435 
436  // Optionally override controlDict time with -time options
438  if (times.size() < 1)
439  {
441  << "No times selected." << exit(FatalError);
442  }
443  forAll(times, timei)
444  {
445  word instance;
446  if (args.optionFound("instance"))
447  {
448  if (times.size() > 1)
449  {
451  << "Multiple times selected with 'instance' option"
452  << exit(FatalError);
453  }
454 
455  args.optionLookup("instance")() >> instance;
456  }
457  else
458  {
459  runTime.setTime(times[timei], timei);
460  instance = runTime.name();
461  }
462 
463  #include "createNamedMesh.H"
464 
465  const bool literalRE = args.optionFound("literalRE");
466  if (literalRE)
467  {
468  Info<< "Not interpreting any regular expressions (RE)"
469  << " in the changeDictionaryDict." << endl
470  << "Instead they are handled as any other entry, i.e. added if"
471  << " not present." << endl;
472  }
473 
474  const bool enableEntries = args.optionFound("enableFunctionEntries");
475  if (enableEntries)
476  {
477  Info<< "Allowing dictionary preprocessing "
478  "('#include', '#codeStream')."
479  << endl;
480  }
481 
482  int oldFlag = entry::disableFunctionEntries;
483  if (!enableEntries)
484  {
485  // By default disable dictionary expansion for fields
487  }
488 
489 
490  const bool disablePatchGroups = args.optionFound("disablePatchGroups");
491  if (disablePatchGroups)
492  {
493  Info<< "Not interpreting any keys in the changeDictionary"
494  << " as patchGroups"
495  << endl;
496  }
497 
498 
499  fileName regionPrefix = "";
501  {
502  regionPrefix = regionName;
503  }
504 
505 
506  // Make sure we do not use the master-only reading since we read
507  // fields (different per processor) as dictionaries.
509 
510 
511  // Get the replacement rules from a dictionary
512  const dictionary dict(systemDict("changeDictionaryDict", args, mesh));
513 
514  const dictionary* replaceDictsPtr = &dict;
515 
516  if (args.optionFound("subDict"))
517  {
518  word subDictName(args.optionLookup("subDict")());
519  replaceDictsPtr = &dict.subDict(subDictName);
520  }
521 
522  const dictionary& replaceDicts = *replaceDictsPtr;
523 
524  Info<< "Read dictionary " << dict.name()
525  << " with replacements for dictionaries "
526  << replaceDicts.toc() << endl;
527 
528 
529 
530  // Always read boundary to get patch groups
531  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
532 
533  Info<< "Reading polyMesh/boundary file to extract patch names"
534  << endl;
535 
536  // Read PtrList of dictionary as dictionary.
537  const word oldTypeName = IOPtrList<entry>::typeName;
539  IOPtrList<entry> dictList
540  (
541  IOobject
542  (
543  "boundary",
544  runTime.findInstance
545  (
546  regionPrefix/polyMesh::meshSubDir,
547  "boundary",
549  ),
551  mesh,
554  false
555  )
556  );
557  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
558 
559  // Fake type back to what was in field
560  const_cast<word&>(dictList.type()) = dictList.headerClassName();
561 
562  // Temporary convert to dictionary
563  dictionary fieldDict;
564  forAll(dictList, i)
565  {
566  fieldDict.add(dictList[i].keyword(), dictList[i].dict());
567  }
568 
569  if (dictList.size())
570  {
571  Info<< "Loaded dictionary " << dictList.name()
572  << " with entries " << fieldDict.toc() << endl;
573  }
574 
575  // Extract any patchGroups information (= shortcut for set of
576  // patches)
577  HashTable<wordList, word> patchGroups;
578  if (!disablePatchGroups)
579  {
580  patchGroups = extractPatchGroups(fieldDict);
581  if (patchGroups.size())
582  {
583  Info<< "Extracted patch groups:" << endl;
584  wordList groups(patchGroups.sortedToc());
585  forAll(groups, i)
586  {
587  Info<< " group " << groups[i] << " with patches "
588  << patchGroups[groups[i]] << endl;
589  }
590  }
591  }
592 
593 
594  // Every replacement is a dictionary name and a keyword in this
595 
596  forAllConstIter(dictionary, replaceDicts, fieldIter)
597  {
598  const word& fieldName = fieldIter().keyword();
599  Info<< "Replacing entries in dictionary " << fieldName << endl;
600 
601  // Handle 'boundary' specially:
602  // - is PtrList of dictionaries
603  // - is in polyMesh/
604  if (fieldName == "boundary")
605  {
606  Info<< "Special handling of " << fieldName
607  << " as polyMesh/boundary file." << endl;
608 
609  // Get the replacement dictionary for the field
610  const dictionary& replaceDict = fieldIter().dict();
611  Info<< "Merging entries from " << replaceDict.toc() << endl;
612 
613  // Merge the replacements in
614  merge(fieldDict, replaceDict, literalRE, patchGroups);
615 
616  Info<< "fieldDict:" << fieldDict << endl;
617 
618  // Convert back into dictList
619  wordList doneKeys(dictList.size());
620 
621  label nEntries = fieldDict.size();
622 
623  forAll(dictList, i)
624  {
625  doneKeys[i] = dictList[i].keyword();
626  dictList.set
627  (
628  i,
629  fieldDict.lookupEntry
630  (
631  doneKeys[i],
632  false,
633  true
634  ).clone()
635  );
636  fieldDict.remove(doneKeys[i]);
637  }
638 
639  // Add remaining entries
640  label sz = dictList.size();
641  dictList.setSize(nEntries);
642  forAllConstIter(dictionary, fieldDict, iter)
643  {
644  dictList.set(sz++, iter().clone());
645  }
646 
647  Info<< "Writing modified " << fieldName << endl;
648  dictList.writeObject
649  (
650  runTime.writeFormat(),
651  runTime.writeFormat(),
653  true
654  );
655  }
656  else
657  {
658  // Read dictionary. (disable class type checking so we can load
659  // field)
660  Info<< "Loading dictionary " << fieldName << endl;
661  const word oldTypeName = localIOdictionary::typeName;
662  const_cast<word&>(localIOdictionary::typeName) = word::null;
663 
664  localIOdictionary fieldDict
665  (
666  IOobject
667  (
668  fieldName,
669  instance,
670  mesh,
673  false
674  )
675  );
676 
677  const_cast<word&>(localIOdictionary::typeName) = oldTypeName;
678 
679  // Fake type back to what was in field
680  const_cast<word&>(fieldDict.type()) =
681  fieldDict.headerClassName();
682 
683  Info<< "Loaded dictionary " << fieldName
684  << " with entries " << fieldDict.toc() << endl;
685 
686  // Get the replacement dictionary for the field
687  const dictionary& replaceDict = fieldIter().dict();
688  Info<< "Merging entries from " << replaceDict.toc() << endl;
689 
690  // Merge the replacements in
691  merge(fieldDict, replaceDict, literalRE, patchGroups);
692 
693  Info<< "Writing modified fieldDict " << fieldName << endl;
694  fieldDict.regIOobject::write();
695  }
696  }
697 
699  }
700 
701  Info<< "\nEnd\n" << endl;
702 
703  return 0;
704 }
705 
706 
707 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A HashTable with keys but without contents.
Definition: HashSet.H:62
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
An STL-conforming iterator.
Definition: HashTable.H:429
An STL-conforming hash table.
Definition: HashTable.H:127
List< Key > sortedToc() const
Return the table of contents as a sorted list.
Definition: HashTable.C:217
bool erase(const iterator &)
Erase a hashedEntry specified by given iterator.
Definition: HashTable.C:371
List< Key > toc() const
Return the table of contents.
Definition: HashTable.C:202
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:142
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
Template class for intrusive linked lists.
Definition: ILList.H:67
A PtrList of objects of type <Type> with automated input and output.
Definition: IOPtrList.H:53
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
@ MUST_READ_IF_MODIFIED
Definition: IOobject.H:119
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:226
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:128
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
IStringStream optionLookup(const word &opt) const
Return an IStringStream from the named option.
Definition: argListI.H:120
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:109
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:698
const entry & lookupEntry(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream if present otherwise error.
Definition: dictionary.C:817
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:1151
bool remove(const word &)
Remove an entry specified by keyword.
Definition: dictionary.C:1332
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:998
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1169
bool readIfPresent(const word &, T &, bool recursive=false, bool patternMatch=true) const
Find an entry if present, and assign to T.
wordList toc() const
Return the table of contents.
Definition: dictionary.C:1131
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:68
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:156
const keyType & keyword() const
Return keyword.
Definition: entry.H:123
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
static int disableFunctionEntries
Definition: entry.H:86
A class for handling file names.
Definition: fileName.H:82
A class for handling keywords in dictionaries.
Definition: keyType.H:69
bool isPattern() const
Should be treated as a match rather than a literal string.
Definition: keyTypeI.H:97
localIOdictionary derived from IOdictionary with global set false to disable parallel master reading.
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:268
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:271
static void addOptions(const bool constant=true, const bool withZero=false)
Add the options handled by timeSelector to argList::validOptions.
Definition: timeSelector.C:114
static instantList selectIfPresent(Time &runTime, const argList &args)
If any time option provided return the set of times (as select0)
Definition: timeSelector.C:283
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
Foam::word regionName
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
int main(int argc, char *argv[])
Definition: financialFoam.C:44
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< word > wordList
A List of words.
Definition: fileName.H:54
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 findStrings(const wordReListMatcher &matcher, const std::string &str)
Return true if string matches one of the regular expressions.
Definition: stringListOps.H:52
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion)
Definition: systemDict.C:92
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
messageStream Info
T clone(const T &t)
Definition: List.H:55
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
defineTemplateTypeNameAndDebug(IOPtrList< ensightPart >, 0)
static const char nl
Definition: Ostream.H:260
messageStream Warning
dictionary dict
Foam::argList args(argc, argv)
Operations on lists of strings.
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:112