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