Initial commit for version 2.0.x patch release
[OpenFOAM-2.0.x.git] / applications / utilities / preProcessing / changeDictionary / changeDictionary.C
blob9dd677a61a51999105f4182a40b8de1cf8290d1e
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2004-2011 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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.
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.
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/>.
24 Application
25     changeDictionary
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.
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     dictionaryReplacement
37     {
38         p                           // field to change
39         {
40             boundaryField
41             {
42                 ".*Wall"            // entry to change
43                 {
44                     type            zeroGradient;
45                 }
46                 movingWall          // entry to change
47                 {
48                     type            fixedValue;
49                     value           uniform 123.45;
50                 }
51             }
52         }
53     }
54     \endverbatim
56 Usage
58     - changeDictionary [OPTION]
60     \param -literalRE \n
61     Do not interpret regular expressions; treat them as any other keyword.
63     \param -enableFunctionEntries \n
64     By default all dictionary preprocessing of fields is disabled
66 \*---------------------------------------------------------------------------*/
68 #include "argList.H"
69 #include "IOobjectList.H"
70 #include "IOPtrList.H"
71 #include "volFields.H"
72 #include "stringListOps.H"
74 using namespace Foam;
76 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
78 namespace Foam
80     defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
86 bool merge(dictionary&, const dictionary&, const bool);
89 // Add thisEntry to dictionary thisDict.
90 bool addEntry
92     dictionary& thisDict,
93     entry& thisEntry,
94     const entry& mergeEntry,
95     const bool literalRE
98     bool changed = false;
100     // Recursively merge sub-dictionaries
101     // TODO: merge without copying
102     if (thisEntry.isDict() && mergeEntry.isDict())
103     {
104         if
105         (
106             merge
107             (
108                 const_cast<dictionary&>(thisEntry.dict()),
109                 mergeEntry.dict(),
110                 literalRE
111             )
112         )
113         {
114             changed = true;
115         }
116     }
117     else
118     {
119         // Should use in-place modification instead of adding
120         thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
121         changed = true;
122     }
124     return changed;
128 // Dictionary merging/editing.
129 // literalRE:
130 // - true: behave like dictionary::merge, i.e. add regexps just like
131 //   any other key.
132 // - false : interpret wildcard as a rule for items to be matched.
133 bool merge
135     dictionary& thisDict,
136     const dictionary& mergeDict,
137     const bool literalRE
140     bool changed = false;
142     // Save current (non-wildcard) keys before adding items.
143     HashSet<word> thisKeysSet;
144     {
145         List<keyType> keys = thisDict.keys(false);
146         forAll(keys, i)
147         {
148             thisKeysSet.insert(keys[i]);
149         }
150     }
152     // Pass 1. All literal matches
154     forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
155     {
156         const keyType& key = mergeIter().keyword();
158         if (literalRE || !key.isPattern())
159         {
160             entry* entryPtr = thisDict.lookupEntryPtr
161             (
162                 key,
163                 false,              // recursive
164                 false               // patternMatch
165             );
167             if (entryPtr)
168             {
170                 // Mark thisDict entry as having been match for wildcard
171                 // handling later on.
172                 thisKeysSet.erase(entryPtr->keyword());
174                 if
175                 (
176                     addEntry
177                     (
178                         thisDict,
179                        *entryPtr,
180                         mergeIter(),
181                         literalRE
182                     )
183                 )
184                 {
185                     changed = true;
186                 }
187             }
188             else
189             {
190                 // not found - just add
191                 thisDict.add(mergeIter().clone(thisDict).ptr());
192                 changed = true;
193             }
194         }
195     }
198     // Pass 2. Wildcard matches (if any) on any non-match keys.
200     if (!literalRE && thisKeysSet.size() > 0)
201     {
202         wordList thisKeys(thisKeysSet.toc());
204         forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
205         {
206             const keyType& key = mergeIter().keyword();
208             if (key.isPattern())
209             {
210                 // Find all matching entries in the original thisDict
212                 labelList matches = findStrings(key, thisKeys);
214                 forAll(matches, i)
215                 {
216                     label matchI = matches[i];
218                     entry& thisEntry = const_cast<entry&>
219                     (
220                         thisDict.lookupEntry(thisKeys[matchI], false, false)
221                     );
223                     if
224                     (
225                         addEntry
226                         (
227                             thisDict,
228                             thisEntry,
229                             mergeIter(),
230                             literalRE
231                         )
232                     )
233                     {
234                         changed = true;
235                     }
236                 }
237             }
238         }
239     }
241     return changed;
245 // Main program:
247 int main(int argc, char *argv[])
249     argList::addOption
250     (
251         "instance",
252         "name",
253         "specify alternate time instance - default is latest time"
254     );
255     argList::addBoolOption
256     (
257         "literalRE",
258         "treat regular expressions literally (ie, as a keyword)"
259     );
260     argList::addBoolOption
261     (
262         "enableFunctionEntries",
263         "enable expansion of dictionary directives - #include, #codeStream etc"
264     );
265     #include "addRegionOption.H"
267     #include "setRootCase.H"
268     #include "createTime.H"
269     #include "createNamedMesh.H"
271     const bool literalRE = args.optionFound("literalRE");
273     if (literalRE)
274     {
275         Info<< "Not interpreting any regular expressions (RE)"
276             << " in the changeDictionaryDict." << endl
277             << "Instead they are handled as any other entry, i.e. added if"
278             << " not present." << endl;
279     }
281     const bool enableEntries = args.optionFound("enableFunctionEntries");
282     if (enableEntries)
283     {
284         Info<< "Allowing dictionary preprocessing ('#include', '#codeStream')."
285             << endl;
286     }
288     int oldFlag = entry::disableFunctionEntries;
289     if (!enableEntries)
290     {
291         // By default disable dictionary expansion for fields
292         entry::disableFunctionEntries = 1;
293     }
296     fileName regionPrefix = "";
297     if (regionName != fvMesh::defaultRegion)
298     {
299         regionPrefix = regionName;
300     }
302     word instance = runTime.timeName();
303     if (args.options().found("instance"))
304     {
305         instance = args.options()["instance"];
306     }
308     // Make sure we do not use the master-only reading since we read
309     // fields (different per processor) as dictionaries.
310     regIOobject::fileModificationChecking = regIOobject::timeStamp;
313     // Get the replacement rules from a dictionary
314     IOdictionary dict
315     (
316         IOobject
317         (
318             "changeDictionaryDict",
319             runTime.system(),
320             mesh,
321             IOobject::MUST_READ_IF_MODIFIED,
322             IOobject::NO_WRITE
323         )
324     );
325     const dictionary& replaceDicts = dict.subDict("dictionaryReplacement");
326     Info<< "Read dictionary " << dict.name()
327         << " with replacements for dictionaries "
328         << replaceDicts.toc() << endl;
331     // Every replacement is a dictionary name and a keyword in this
333     forAllConstIter(dictionary, replaceDicts, fieldIter)
334     {
335         const word& fieldName = fieldIter().keyword();
336         Info<< "Replacing entries in dictionary " << fieldName << endl;
338         // Handle 'boundary' specially:
339         // - is PtrList of dictionaries
340         // - is in polyMesh/
341         if (fieldName == "boundary")
342         {
343             Info<< "Special handling of " << fieldName
344                 << " as polyMesh/boundary file." << endl;
346             // Read PtrList of dictionary as dictionary.
347             const word oldTypeName = IOPtrList<entry>::typeName;
348             const_cast<word&>(IOPtrList<entry>::typeName) = word::null;
349             IOPtrList<entry> dictList
350             (
351                 IOobject
352                 (
353                     fieldName,
354                     runTime.findInstance
355                     (
356                         regionPrefix/polyMesh::meshSubDir,
357                         fieldName
358                     ),
359                     polyMesh::meshSubDir,
360                     mesh,
361                     IOobject::MUST_READ,
362                     IOobject::NO_WRITE,
363                     false
364                 )
365             );
366             const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
367             // Fake type back to what was in field
368             const_cast<word&>(dictList.type()) = dictList.headerClassName();
370             // Temporary convert to dictionary
371             dictionary fieldDict;
372             forAll(dictList, i)
373             {
374                 fieldDict.add(dictList[i].keyword(), dictList[i].dict());
375             }
377             Info<< "Loaded dictionary " << fieldName
378                 << " with entries " << fieldDict.toc() << endl;
380             // Get the replacement dictionary for the field
381             const dictionary& replaceDict = fieldIter().dict();
382             Info<< "Merging entries from " << replaceDict.toc() << endl;
384             // Merge the replacements in
385             merge(fieldDict, replaceDict, literalRE);
387             Info<< "fieldDict:" << fieldDict << endl;
389             // Convert back into dictList
390             wordList doneKeys(dictList.size());
392             label nEntries = fieldDict.size();
393             forAll(dictList, i)
394             {
395                 doneKeys[i] = dictList[i].keyword();
396                 dictList.set
397                 (
398                     i,
399                     fieldDict.lookupEntry
400                     (
401                         doneKeys[i],
402                         false,
403                         true
404                     ).clone()
405                 );
406                 fieldDict.remove(doneKeys[i]);
407             }
408             // Add remaining entries
409             label sz = dictList.size();
410             dictList.setSize(nEntries);
411             forAllConstIter(dictionary, fieldDict, iter)
412             {
413                 dictList.set(sz, iter().clone());
414             }
416             Info<< "Writing modified fieldDict " << fieldName << endl;
417             dictList.write();
418         }
419         else
420         {
421             // Read dictionary. (disable class type checking so we can load
422             // field)
423             Info<< "Loading dictionary " << fieldName << endl;
424             const word oldTypeName = IOdictionary::typeName;
425             const_cast<word&>(IOdictionary::typeName) = word::null;
427             IOdictionary fieldDict
428             (
429                 IOobject
430                 (
431                     fieldName,
432                     instance,
433                     mesh,
434                     IOobject::MUST_READ_IF_MODIFIED,
435                     IOobject::NO_WRITE,
436                     false
437                 )
438             );
440             const_cast<word&>(IOdictionary::typeName) = oldTypeName;
441             // Fake type back to what was in field
442             const_cast<word&>(fieldDict.type()) = fieldDict.headerClassName();
444             Info<< "Loaded dictionary " << fieldName
445                 << " with entries " << fieldDict.toc() << endl;
447             // Get the replacement dictionary for the field
448             const dictionary& replaceDict = fieldIter().dict();
449             Info<< "Merging entries from " << replaceDict.toc() << endl;
451             // Merge the replacements in
452             merge(fieldDict, replaceDict, literalRE);
454             Info<< "Writing modified fieldDict " << fieldName << endl;
455             fieldDict.regIOobject::write();
456         }
457     }
459     entry::disableFunctionEntries = oldFlag;
461     Info<< endl;
463     Info<< "End\n" << endl;
465     return 0;
469 // ************************************************************************* //