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