1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2011 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
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
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/>.
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:
42 ".*Wall" // entry to change
46 movingWall // entry to change
58 - changeDictionary [OPTION]
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 \*---------------------------------------------------------------------------*/
69 #include "IOobjectList.H"
70 #include "IOPtrList.H"
71 #include "volFields.H"
72 #include "stringListOps.H"
76 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
80 defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
86 bool merge(dictionary&, const dictionary&, const bool);
89 // Add thisEntry to dictionary thisDict.
94 const entry& mergeEntry,
100 // Recursively merge sub-dictionaries
101 // TODO: merge without copying
102 if (thisEntry.isDict() && mergeEntry.isDict())
108 const_cast<dictionary&>(thisEntry.dict()),
119 // Should use in-place modification instead of adding
120 thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
128 // Dictionary merging/editing.
130 // - true: behave like dictionary::merge, i.e. add regexps just like
132 // - false : interpret wildcard as a rule for items to be matched.
135 dictionary& thisDict,
136 const dictionary& mergeDict,
140 bool changed = false;
142 // Save current (non-wildcard) keys before adding items.
143 HashSet<word> thisKeysSet;
145 List<keyType> keys = thisDict.keys(false);
148 thisKeysSet.insert(keys[i]);
152 // Pass 1. All literal matches
154 forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
156 const keyType& key = mergeIter().keyword();
158 if (literalRE || !key.isPattern())
160 entry* entryPtr = thisDict.lookupEntryPtr
164 false // patternMatch
170 // Mark thisDict entry as having been match for wildcard
171 // handling later on.
172 thisKeysSet.erase(entryPtr->keyword());
190 // not found - just add
191 thisDict.add(mergeIter().clone(thisDict).ptr());
198 // Pass 2. Wildcard matches (if any) on any non-match keys.
200 if (!literalRE && thisKeysSet.size() > 0)
202 wordList thisKeys(thisKeysSet.toc());
204 forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
206 const keyType& key = mergeIter().keyword();
210 // Find all matching entries in the original thisDict
212 labelList matches = findStrings(key, thisKeys);
216 label matchI = matches[i];
218 entry& thisEntry = const_cast<entry&>
220 thisDict.lookupEntry(thisKeys[matchI], false, false)
247 int main(int argc, char *argv[])
253 "specify alternate time instance - default is latest time"
255 argList::addBoolOption
258 "treat regular expressions literally (ie, as a keyword)"
260 argList::addBoolOption
262 "enableFunctionEntries",
263 "enable expansion of dictionary directives - #include, #codeStream etc"
265 #include "addRegionOption.H"
267 #include "setRootCase.H"
268 #include "createTime.H"
269 #include "createNamedMesh.H"
271 const bool literalRE = args.optionFound("literalRE");
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;
281 const bool enableEntries = args.optionFound("enableFunctionEntries");
284 Info<< "Allowing dictionary preprocessing ('#include', '#codeStream')."
288 int oldFlag = entry::disableFunctionEntries;
291 // By default disable dictionary expansion for fields
292 entry::disableFunctionEntries = 1;
296 fileName regionPrefix = "";
297 if (regionName != fvMesh::defaultRegion)
299 regionPrefix = regionName;
302 word instance = runTime.timeName();
303 if (args.options().found("instance"))
305 instance = args.options()["instance"];
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
318 "changeDictionaryDict",
321 IOobject::MUST_READ_IF_MODIFIED,
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)
335 const word& fieldName = fieldIter().keyword();
336 Info<< "Replacing entries in dictionary " << fieldName << endl;
338 // Handle 'boundary' specially:
339 // - is PtrList of dictionaries
341 if (fieldName == "boundary")
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
356 regionPrefix/polyMesh::meshSubDir,
359 polyMesh::meshSubDir,
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;
374 fieldDict.add(dictList[i].keyword(), dictList[i].dict());
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();
395 doneKeys[i] = dictList[i].keyword();
399 fieldDict.lookupEntry
406 fieldDict.remove(doneKeys[i]);
408 // Add remaining entries
409 label sz = dictList.size();
410 dictList.setSize(nEntries);
411 forAllConstIter(dictionary, fieldDict, iter)
413 dictList.set(sz, iter().clone());
416 Info<< "Writing modified fieldDict " << fieldName << endl;
421 // Read dictionary. (disable class type checking so we can load
423 Info<< "Loading dictionary " << fieldName << endl;
424 const word oldTypeName = IOdictionary::typeName;
425 const_cast<word&>(IOdictionary::typeName) = word::null;
427 IOdictionary fieldDict
434 IOobject::MUST_READ_IF_MODIFIED,
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();
459 entry::disableFunctionEntries = oldFlag;
463 Info<< "End\n" << endl;
469 // ************************************************************************* //