FreeFOAM The Cross-Platform CFD Toolkit
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) 1991-2010 OpenCFD Ltd.
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.
29 
30  Reads dictionaries (fields) and entries to change from a dictionary.
31  E.g. to make the @em movingWall a @em fixedValue for @em p but all other
32  @em Walls a zeroGradient boundary condition, the
33  @c system/changeDictionaryDict would contain the following:
34  @verbatim
35  dictionaryReplacement
36  {
37  p // field to change
38  {
39  boundaryField
40  {
41  ".*Wall" // entry to change
42  {
43  type zeroGradient;
44  }
45  movingWall // entry to change
46  {
47  type fixedValue;
48  value uniform 123.45;
49  }
50  }
51  }
52  }
53  @endverbatim
54 
55 
56 Usage
57 
58  - changeDictionary [OPTIONS]
59 
60  @param -literalRE \n
61  Do not interpret regular expressions; treat them as any other keyword.
62 
63  @param -region <name>\n
64  Only apply to named mesh region.
65 
66  @param -case <dir>\n
67  Case directory.
68 
69  @param -parallel \n
70  Run in parallel.
71 
72  @param -help \n
73  Display help message.
74 
75  @param -doc \n
76  Display Doxygen API documentation page for this application.
77 
78  @param -srcDoc \n
79  Display Doxygen source documentation page for this application.
80 
81 \*---------------------------------------------------------------------------*/
82 
83 #include <OpenFOAM/argList.H>
84 #include <OpenFOAM/IOobjectList.H>
85 #include <OpenFOAM/IOPtrList.H>
86 #include <finiteVolume/volFields.H>
87 #include <OpenFOAM/stringListOps.H>
88 
89 using namespace Foam;
90 
91 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
92 
93 namespace Foam
94 {
96 }
97 
98 
99 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
100 
101 bool merge(dictionary&, const dictionary&, const bool);
102 
103 
104 // Add thisEntry to dictionary thisDict.
105 bool addEntry
106 (
107  dictionary& thisDict,
108  entry& thisEntry,
109  const entry& mergeEntry,
110  const bool literalRE
111 )
112 {
113  bool changed = false;
114 
115  // Recursively merge sub-dictionaries
116  // TODO: merge without copying
117  if (thisEntry.isDict() && mergeEntry.isDict())
118  {
119  if
120  (
121  merge
122  (
123  const_cast<dictionary&>(thisEntry.dict()),
124  mergeEntry.dict(),
125  literalRE
126  )
127  )
128  {
129  changed = true;
130  }
131  }
132  else
133  {
134  // Should use in-place modification instead of adding
135  thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
136  changed = true;
137  }
138 
139  return changed;
140 }
141 
142 
143 // Dictionary merging/editing.
144 // literalRE:
145 // - true: behave like dictionary::merge, i.e. add regexps just like
146 // any other key.
147 // - false : interpret wildcard as a rule for items to be matched.
148 bool merge
149 (
150  dictionary& thisDict,
151  const dictionary& mergeDict,
152  const bool literalRE
153 )
154 {
155  static bool wildCardInMergeDict = false;
156 
157  bool changed = false;
158 
159  // Save current (non-wildcard) keys before adding items.
160  HashSet<word> thisKeysSet;
161  {
162  List<keyType> keys = thisDict.keys(false);
163  forAll(keys, i)
164  {
165  thisKeysSet.insert(keys[i]);
166  }
167  }
168 
169  // Pass 1. All literal matches
170 
171  forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
172  {
173  const keyType& key = mergeIter().keyword();
174 
175  if (literalRE || !key.isPattern())
176  {
177  entry* entryPtr = thisDict.lookupEntryPtr
178  (
179  key,
180  false, // recursive
181  false // patternMatch
182  );
183 
184  if (entryPtr)
185  {
186 
187  // Mark thisDict entry as having been match for wildcard
188  // handling later on.
189  thisKeysSet.erase(entryPtr->keyword());
190 
191  if
192  (
193  addEntry
194  (
195  thisDict,
196  *entryPtr,
197  mergeIter(),
198  literalRE
199  )
200  )
201  {
202  changed = true;
203  }
204  }
205  else
206  {
207  // not found - just add
208  thisDict.add(mergeIter().clone(thisDict).ptr());
209  changed = true;
210  }
211  }
212  }
213 
214 
215  // Pass 2. Wildcard matches (if any) on any non-match keys.
216 
217  if (!literalRE && thisKeysSet.size() > 0)
218  {
219  wordList thisKeys(thisKeysSet.toc());
220 
221  forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
222  {
223  const keyType& key = mergeIter().keyword();
224 
225  if (key.isPattern())
226  {
227  // Find all matching entries in the original thisDict
228 
229  if (!wildCardInMergeDict)
230  {
231  wildCardInMergeDict = true;
232  WarningIn("changeDictionary()")
233  << "Detected wildcard " << key
234  << " in changeDictionaryDict" << endl
235  << "The behaviour of wildcards has changed -"
236  << " they are now interpreted by changeDictionary."
237  << endl << "Please take care or use the -literalRE"
238  << " command line option to revert to"
239  << " previous behaviour." << endl;
240  }
241 
242  labelList matches = findStrings(key, thisKeys);
243 
244  forAll(matches, i)
245  {
246  label matchI = matches[i];
247 
248  entry& thisEntry = const_cast<entry&>
249  (
250  thisDict.lookupEntry(thisKeys[matchI], false, false)
251  );
252 
253  if
254  (
255  addEntry
256  (
257  thisDict,
258  thisEntry,
259  mergeIter(),
260  literalRE
261  )
262  )
263  {
264  changed = true;
265  }
266  }
267  }
268  }
269  }
270 
271  return changed;
272 }
273 
274 
275 // Main program:
276 
277 int main(int argc, char *argv[])
278 {
279  argList::validOptions.insert("instance", "instance");
280  argList::validOptions.insert("literalRE", "");
281  #include <OpenFOAM/addRegionOption.H>
282 
283  #include <OpenFOAM/setRootCase.H>
284  #include <OpenFOAM/createTime.H>
285  #include <OpenFOAM/createNamedMesh.H>
286 
287  bool literalRE = args.optionFound("literalRE");
288 
289  if (literalRE)
290  {
291  Info<< "Not interpreting any regular expressions (RE)"
292  << " in the changeDictionaryDict." << endl
293  << "Instead they are handled as any other entry, i.e. added if"
294  << " not present." << endl;
295  }
296 
297 
298  fileName regionPrefix = "";
300  {
301  regionPrefix = regionName;
302  }
303 
304  word instance = runTime.timeName();
305  if (args.options().found("instance"))
306  {
307  instance = args.options()["instance"];
308  }
309 
310  // Get the replacement rules from a dictionary
311  IOdictionary dict
312  (
313  IOobject
314  (
315  "changeDictionaryDict",
316  runTime.system(),
317  mesh,
320  )
321  );
322  const dictionary& replaceDicts = dict.subDict("dictionaryReplacement");
323  Info<< "Read dictionary " << dict.name()
324  << " with replacements for dictionaries "
325  << replaceDicts.toc() << endl;
326 
327 
328  // Every replacement is a dictionary name and a keyword in this
329 
330  forAllConstIter(dictionary, replaceDicts, fieldIter)
331  {
332  const word& fieldName = fieldIter().keyword();
333  Info<< "Replacing entries in dictionary " << fieldName << endl;
334 
335  // Handle 'boundary' specially:
336  // - is PtrList of dictionaries
337  // - is in polyMesh/
338  if (fieldName == "boundary")
339  {
340  Info<< "Special handling of " << fieldName
341  << " as polyMesh/boundary file." << endl;
342 
343  // Read PtrList of dictionary as dictionary.
344  const word oldTypeName = IOPtrList<entry>::typeName;
346  IOPtrList<entry> dictList
347  (
348  IOobject
349  (
350  fieldName,
351  runTime.findInstance
352  (
353  regionPrefix/polyMesh::meshSubDir,
354  fieldName
355  ),
357  mesh,
360  false
361  )
362  );
363  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
364  // Fake type back to what was in field
365  const_cast<word&>(dictList.type()) = dictList.headerClassName();
366 
367  // Temporary convert to dictionary
368  dictionary fieldDict;
369  forAll(dictList, i)
370  {
371  fieldDict.add(dictList[i].keyword(), dictList[i].dict());
372  }
373 
374  Info<< "Loaded dictionary " << fieldName
375  << " with entries " << fieldDict.toc() << endl;
376 
377  // Get the replacement dictionary for the field
378  const dictionary& replaceDict = fieldIter().dict();
379  Info<< "Merging entries from " << replaceDict.toc() << endl;
380 
381  // Merge the replacements in
382  merge(fieldDict, replaceDict, literalRE);
383 
384  Info<< "fieldDict:" << fieldDict << endl;
385 
386  // Convert back into dictList
387  wordList doneKeys(dictList.size());
388 
389  label nEntries = fieldDict.size();
390  forAll(dictList, i)
391  {
392  doneKeys[i] = dictList[i].keyword();
393  dictList.set
394  (
395  i,
396  fieldDict.lookupEntry
397  (
398  doneKeys[i],
399  false,
400  true
401  ).clone()
402  );
403  fieldDict.remove(doneKeys[i]);
404  }
405  // Add remaining entries
406  label sz = dictList.size();
407  dictList.setSize(nEntries);
408  forAllConstIter(dictionary, fieldDict, iter)
409  {
410  dictList.set(sz, iter().clone());
411  }
412 
413  Info<< "Writing modified fieldDict " << fieldName << endl;
414  dictList.write();
415  }
416  else
417  {
418  // Read dictionary. (disable class type checking so we can load
419  // field)
420  Info<< "Loading dictionary " << fieldName << endl;
421  const word oldTypeName = IOdictionary::typeName;
422  const_cast<word&>(IOdictionary::typeName) = word::null;
423 
424  IOdictionary fieldDict
425  (
426  IOobject
427  (
428  fieldName,
429  instance,
430  mesh,
433  false
434  )
435  );
436  const_cast<word&>(IOdictionary::typeName) = oldTypeName;
437  // Fake type back to what was in field
438  const_cast<word&>(fieldDict.type()) = fieldDict.headerClassName();
439 
440  Info<< "Loaded dictionary " << fieldName
441  << " with entries " << fieldDict.toc() << endl;
442 
443  // Get the replacement dictionary for the field
444  const dictionary& replaceDict = fieldIter().dict();
445  Info<< "Merging entries from " << replaceDict.toc() << endl;
446 
447  // Merge the replacements in
448  merge(fieldDict, replaceDict, literalRE);
449 
450  Info<< "Writing modified fieldDict " << fieldName << endl;
451  fieldDict.regIOobject::write();
452  }
453  }
454 
455  Info<< endl;
456 
457  Info<< "End\n" << endl;
458 
459  return 0;
460 }
461 
462 
463 // ************************ vim: set sw=4 sts=4 et: ************************ //