FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

changeDictionary.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 Application
00025     changeDictionary
00026 
00027 Description
00028     Utility to change dictionary entries.
00029 
00030     Reads dictionaries (fields) and entries to change from a dictionary.
00031     E.g. to make the @em movingWall a @em fixedValue for @em p but all other
00032     @em Walls a zeroGradient boundary condition, the
00033     @c system/changeDictionaryDict would contain the following:
00034     @verbatim
00035     dictionaryReplacement
00036     {
00037         p                           // field to change
00038         {
00039             boundaryField
00040             {
00041                 ".*Wall"            // entry to change
00042                 {
00043                     type            zeroGradient;
00044                 }
00045                 movingWall          // entry to change
00046                 {
00047                     type            fixedValue;
00048                     value           uniform 123.45;
00049                 }
00050             }
00051         }
00052     }
00053     @endverbatim
00054 
00055 
00056 Usage
00057 
00058     - changeDictionary [OPTIONS]
00059 
00060     @param -literalRE \n
00061     Do not interpret regular expressions; treat them as any other keyword.
00062 
00063     @param -region <name>\n
00064     Only apply to named mesh region.
00065 
00066     @param -case <dir>\n
00067     Case directory.
00068 
00069     @param -parallel \n
00070     Run in parallel.
00071 
00072     @param -help \n
00073     Display help message.
00074 
00075     @param -doc \n
00076     Display Doxygen API documentation page for this application.
00077 
00078     @param -srcDoc \n
00079     Display Doxygen source documentation page for this application.
00080 
00081 \*---------------------------------------------------------------------------*/
00082 
00083 #include <OpenFOAM/argList.H>
00084 #include <OpenFOAM/IOobjectList.H>
00085 #include <OpenFOAM/IOPtrList.H>
00086 #include <finiteVolume/volFields.H>
00087 #include <OpenFOAM/stringListOps.H>
00088 
00089 using namespace Foam;
00090 
00091 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00092 
00093 namespace Foam
00094 {
00095     defineTemplateTypeNameAndDebug(IOPtrList<entry>, 0);
00096 }
00097 
00098 
00099 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00100 
00101 bool merge(dictionary&, const dictionary&, const bool);
00102 
00103 
00104 // Add thisEntry to dictionary thisDict.
00105 bool addEntry
00106 (
00107     dictionary& thisDict,
00108     entry& thisEntry,
00109     const entry& mergeEntry,
00110     const bool literalRE
00111 )
00112 {
00113     bool changed = false;
00114 
00115     // Recursively merge sub-dictionaries
00116     // TODO: merge without copying
00117     if (thisEntry.isDict() && mergeEntry.isDict())
00118     {
00119         if
00120         (
00121             merge
00122             (
00123                 const_cast<dictionary&>(thisEntry.dict()),
00124                 mergeEntry.dict(),
00125                 literalRE
00126             )
00127         )
00128         {
00129             changed = true;
00130         }
00131     }
00132     else
00133     {
00134         // Should use in-place modification instead of adding
00135         thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
00136         changed = true;
00137     }
00138 
00139     return changed;
00140 }
00141 
00142 
00143 // Dictionary merging/editing.
00144 // literalRE:
00145 // - true: behave like dictionary::merge, i.e. add regexps just like
00146 //   any other key.
00147 // - false : interpret wildcard as a rule for items to be matched.
00148 bool merge
00149 (
00150     dictionary& thisDict,
00151     const dictionary& mergeDict,
00152     const bool literalRE
00153 )
00154 {
00155     static bool wildCardInMergeDict = false;
00156 
00157     bool changed = false;
00158 
00159     // Save current (non-wildcard) keys before adding items.
00160     HashSet<word> thisKeysSet;
00161     {
00162         List<keyType> keys = thisDict.keys(false);
00163         forAll(keys, i)
00164         {
00165             thisKeysSet.insert(keys[i]);
00166         }
00167     }
00168 
00169     // Pass 1. All literal matches
00170 
00171     forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
00172     {
00173         const keyType& key = mergeIter().keyword();
00174 
00175         if (literalRE || !key.isPattern())
00176         {
00177             entry* entryPtr = thisDict.lookupEntryPtr
00178             (
00179                 key,
00180                 false,              // recursive
00181                 false               // patternMatch
00182             );
00183 
00184             if (entryPtr)
00185             {
00186 
00187                 // Mark thisDict entry as having been match for wildcard
00188                 // handling later on.
00189                 thisKeysSet.erase(entryPtr->keyword());
00190 
00191                 if
00192                 (
00193                     addEntry
00194                     (
00195                         thisDict,
00196                        *entryPtr,
00197                         mergeIter(),
00198                         literalRE
00199                     )
00200                 )
00201                 {
00202                     changed = true;
00203                 }
00204             }
00205             else
00206             {
00207                 // not found - just add
00208                 thisDict.add(mergeIter().clone(thisDict).ptr());
00209                 changed = true;
00210             }
00211         }
00212     }
00213 
00214 
00215     // Pass 2. Wildcard matches (if any) on any non-match keys.
00216 
00217     if (!literalRE && thisKeysSet.size() > 0)
00218     {
00219         wordList thisKeys(thisKeysSet.toc());
00220 
00221         forAllConstIter(IDLList<entry>, mergeDict, mergeIter)
00222         {
00223             const keyType& key = mergeIter().keyword();
00224 
00225             if (key.isPattern())
00226             {
00227                 // Find all matching entries in the original thisDict
00228 
00229                 if (!wildCardInMergeDict)
00230                 {
00231                     wildCardInMergeDict = true;
00232                     WarningIn("changeDictionary()")
00233                         << "Detected wildcard " << key
00234                         << " in changeDictionaryDict" << endl
00235                         << "The behaviour of wildcards has changed -"
00236                         << " they are now interpreted by changeDictionary."
00237                         << endl << "Please take care or use the -literalRE"
00238                         << " command line option to revert to"
00239                         << " previous behaviour." << endl;
00240                 }
00241 
00242                 labelList matches = findStrings(key, thisKeys);
00243 
00244                 forAll(matches, i)
00245                 {
00246                     label matchI = matches[i];
00247 
00248                     entry& thisEntry = const_cast<entry&>
00249                     (
00250                         thisDict.lookupEntry(thisKeys[matchI], false, false)
00251                     );
00252 
00253                     if
00254                     (
00255                         addEntry
00256                         (
00257                             thisDict,
00258                             thisEntry,
00259                             mergeIter(),
00260                             literalRE
00261                         )
00262                     )
00263                     {
00264                         changed = true;
00265                     }
00266                 }
00267             }
00268         }
00269     }
00270 
00271     return changed;
00272 }
00273 
00274 
00275 // Main program:
00276 
00277 int main(int argc, char *argv[])
00278 {
00279     argList::validOptions.insert("instance", "instance");
00280     argList::validOptions.insert("literalRE", "");
00281     #include <OpenFOAM/addRegionOption.H>
00282 
00283     #include <OpenFOAM/setRootCase.H>
00284     #include <OpenFOAM/createTime.H>
00285     #include <OpenFOAM/createNamedMesh.H>
00286 
00287     bool literalRE = args.optionFound("literalRE");
00288 
00289     if (literalRE)
00290     {
00291         Info<< "Not interpreting any regular expressions (RE)"
00292             << " in the changeDictionaryDict." << endl
00293             << "Instead they are handled as any other entry, i.e. added if"
00294             << " not present." << endl;
00295     }
00296 
00297 
00298     fileName regionPrefix = "";
00299     if (regionName != fvMesh::defaultRegion)
00300     {
00301         regionPrefix = regionName;
00302     }
00303 
00304     word instance = runTime.timeName();
00305     if (args.options().found("instance"))
00306     {
00307         instance = args.options()["instance"];
00308     }
00309 
00310     // Get the replacement rules from a dictionary
00311     IOdictionary dict
00312     (
00313         IOobject
00314         (
00315             "changeDictionaryDict",
00316             runTime.system(),
00317             mesh,
00318             IOobject::MUST_READ,
00319             IOobject::NO_WRITE
00320         )
00321     );
00322     const dictionary& replaceDicts = dict.subDict("dictionaryReplacement");
00323     Info<< "Read dictionary " << dict.name()
00324         << " with replacements for dictionaries "
00325         << replaceDicts.toc() << endl;
00326 
00327 
00328     // Every replacement is a dictionary name and a keyword in this
00329 
00330     forAllConstIter(dictionary, replaceDicts, fieldIter)
00331     {
00332         const word& fieldName = fieldIter().keyword();
00333         Info<< "Replacing entries in dictionary " << fieldName << endl;
00334 
00335         // Handle 'boundary' specially:
00336         // - is PtrList of dictionaries
00337         // - is in polyMesh/
00338         if (fieldName == "boundary")
00339         {
00340             Info<< "Special handling of " << fieldName
00341                 << " as polyMesh/boundary file." << endl;
00342 
00343             // Read PtrList of dictionary as dictionary.
00344             const word oldTypeName = IOPtrList<entry>::typeName;
00345             const_cast<word&>(IOPtrList<entry>::typeName) = word::null;
00346             IOPtrList<entry> dictList
00347             (
00348                 IOobject
00349                 (
00350                     fieldName,
00351                     runTime.findInstance
00352                     (
00353                         regionPrefix/polyMesh::meshSubDir,
00354                         fieldName
00355                     ),
00356                     polyMesh::meshSubDir,
00357                     mesh,
00358                     IOobject::MUST_READ,
00359                     IOobject::NO_WRITE,
00360                     false
00361                 )
00362             );
00363             const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
00364             // Fake type back to what was in field
00365             const_cast<word&>(dictList.type()) = dictList.headerClassName();
00366 
00367             // Temporary convert to dictionary
00368             dictionary fieldDict;
00369             forAll(dictList, i)
00370             {
00371                 fieldDict.add(dictList[i].keyword(), dictList[i].dict());
00372             }
00373 
00374             Info<< "Loaded dictionary " << fieldName
00375                 << " with entries " << fieldDict.toc() << endl;
00376 
00377             // Get the replacement dictionary for the field
00378             const dictionary& replaceDict = fieldIter().dict();
00379             Info<< "Merging entries from " << replaceDict.toc() << endl;
00380 
00381             // Merge the replacements in
00382             merge(fieldDict, replaceDict, literalRE);
00383 
00384             Info<< "fieldDict:" << fieldDict << endl;
00385 
00386             // Convert back into dictList
00387             wordList doneKeys(dictList.size());
00388 
00389             label nEntries = fieldDict.size();
00390             forAll(dictList, i)
00391             {
00392                 doneKeys[i] = dictList[i].keyword();
00393                 dictList.set
00394                 (
00395                     i,
00396                     fieldDict.lookupEntry
00397                     (
00398                         doneKeys[i],
00399                         false,
00400                         true
00401                     ).clone()
00402                 );
00403                 fieldDict.remove(doneKeys[i]);
00404             }
00405             // Add remaining entries
00406             label sz = dictList.size();
00407             dictList.setSize(nEntries);
00408             forAllConstIter(dictionary, fieldDict, iter)
00409             {
00410                 dictList.set(sz, iter().clone());
00411             }
00412 
00413             Info<< "Writing modified fieldDict " << fieldName << endl;
00414             dictList.write();
00415         }
00416         else
00417         {
00418             // Read dictionary. (disable class type checking so we can load
00419             // field)
00420             Info<< "Loading dictionary " << fieldName << endl;
00421             const word oldTypeName = IOdictionary::typeName;
00422             const_cast<word&>(IOdictionary::typeName) = word::null;
00423 
00424             IOdictionary fieldDict
00425             (
00426                 IOobject
00427                 (
00428                     fieldName,
00429                     instance,
00430                     mesh,
00431                     IOobject::MUST_READ,
00432                     IOobject::NO_WRITE,
00433                     false
00434                 )
00435             );
00436             const_cast<word&>(IOdictionary::typeName) = oldTypeName;
00437             // Fake type back to what was in field
00438             const_cast<word&>(fieldDict.type()) = fieldDict.headerClassName();
00439 
00440             Info<< "Loaded dictionary " << fieldName
00441                 << " with entries " << fieldDict.toc() << endl;
00442 
00443             // Get the replacement dictionary for the field
00444             const dictionary& replaceDict = fieldIter().dict();
00445             Info<< "Merging entries from " << replaceDict.toc() << endl;
00446 
00447             // Merge the replacements in
00448             merge(fieldDict, replaceDict, literalRE);
00449 
00450             Info<< "Writing modified fieldDict " << fieldName << endl;
00451             fieldDict.regIOobject::write();
00452         }
00453     }
00454 
00455     Info<< endl;
00456 
00457     Info<< "End\n" << endl;
00458 
00459     return 0;
00460 }
00461 
00462 
00463 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines