openfoam/applications/utilities/miscellaneous/foamDictionary/foamDictionary.C
Mark Olesen af49eaf625 ENH: default jobControl now under the '~/.OpenFOAM/jobControl' directory
- this implies that jobControl is a user-resource for OpenFOAM.
  It was previously located under $WM_PROJECT_INST_DIR/jobControl,
  but few users will have write access there.

- an unset FOAM_JOB_DIR variable is treated as "~/.OpenFOAM/jobControl",
  which can partially reduce environment clutter.

- provide argList::noJobInfo() to conveniently suppress job-info on an
  individual basis for short-running utilities (eg, foamListTimes) to
  avoid unneeded clutter.
2017-04-03 08:28:15 +02:00

525 lines
14 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
foamDictionary
Description
Interrogates and manipulates dictionaries.
Usage
\b foamDictionary [OPTION] dictionary
- \par -entry \<name\>
Selects an entry
- \par -keywords \<name\>
Prints the keywords (of the selected entry or of the top level if
no entry was selected
- \par -add \<value\>
Adds the entry (should not exist yet)
- \par -set \<value\>
Adds or replaces the entry
- \par -remove
Remove the selected entry
- \par -diff \<dictionary\>
Write differences with respect to the specified dictionary
(or sub entry if -entry specified)
- \par -expand
Read the specified dictionary file, expand the macros etc. and write
the resulting dictionary to standard output.
- \par -includes
List the \c \#include and \c \#includeIfPresent files to standard output
- \par -disableFunctionEntries
Do not expand macros or directives (\#include etc)
Example usage:
- Change simulation to run for one timestep only:
\verbatim
foamDictionary system/controlDict -entry stopAt -set writeNow
\endverbatim
- Change solver:
\verbatim
foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
\endverbatim
- Print bc type:
\verbatim
foamDictionary 0/U -entry boundaryField.movingWall.type
\endverbatim
- Change bc parameter:
\verbatim
foamDictionary 0/U -entry boundaryField.movingWall.value \
-set "uniform (2 0 0)"
\endverbatim
- Change whole bc type:
\verbatim
foamDictionary 0/U -entry boundaryField.movingWall \
-set "{type uniformFixedValue; uniformValue (2 0 0);}"
\endverbatim
- Write the differences with respect to a template dictionary:
\verbatim
foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U
\endverbatim
- Write the differences in boundaryField with respect to a
template dictionary:
\verbatim
foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U \
-entry boundaryField
\endverbatim
- Change patch type:
\verbatim
foamDictionary constant/polyMesh/boundary \
-entry entry0.fixedWalls.type -set patch
\endverbatim
This uses special parsing of Lists which stores these in the
dictionary with keyword 'entryDDD' where DDD is the position
in the dictionary (after ignoring the FoamFile entry).
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "IFstream.H"
#include "OFstream.H"
#include "includeEntry.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Converts old scope syntax to new syntax
word scope(const fileName& entryName)
{
if (entryName.find(':') != string::npos)
{
wordList entryNames(entryName.components(':'));
word entry(entryNames[0]);
for (label i = 1; i < entryNames.size(); i++)
{
entry += word('.') + entryNames[i];
}
return entry;
}
else
{
return entryName;
}
}
//- Extracts dict name and keyword
Pair<word> dictAndKeyword(const word& scopedName)
{
string::size_type i = scopedName.find_last_of(".");
if (i != string::npos)
{
return Pair<word>
(
scopedName.substr(0, i),
scopedName.substr(i+1, string::npos)
);
}
else
{
return Pair<word>("", scopedName);
}
}
const dictionary& lookupScopedDict
(
const dictionary& dict,
const word& subDictName
)
{
if (subDictName == "")
{
return dict;
}
else
{
const entry* entPtr = dict.lookupScopedEntryPtr
(
subDictName,
false,
false
);
if (!entPtr || !entPtr->isDict())
{
FatalIOErrorInFunction(dict)
<< "keyword " << subDictName
<< " is undefined in dictionary "
<< dict.name() << " or is not a dictionary"
<< endl
<< "Valid keywords are " << dict.keys()
<< exit(FatalIOError);
}
return entPtr->dict();
}
}
void remove(dictionary& dict, const dictionary& removeDict)
{
forAllConstIter(dictionary, removeDict, iter)
{
const entry* entPtr = dict.lookupEntryPtr
(
iter().keyword(),
false,
false
);
if (entPtr)
{
if (entPtr->isDict())
{
if (iter().isDict())
{
remove
(
const_cast<dictionary&>(entPtr->dict()),
iter().dict()
);
// Check if dictionary is empty
if (!entPtr->dict().size())
{
dict.remove(iter().keyword());
}
}
}
else if (!iter().isDict())
{
if (*entPtr == iter())
{
dict.remove(iter().keyword());
}
}
}
}
}
int main(int argc, char *argv[])
{
argList::addNote("manipulates dictionaries");
argList::noBanner();
argList::noJobInfo();
argList::validArgs.append("dictionary");
argList::addBoolOption("keywords", "list keywords");
argList::addOption("entry", "name", "report/select the named entry");
argList::addBoolOption
(
"value",
"Print entry value"
);
argList::addOption
(
"set",
"value",
"Set entry value or add new entry"
);
argList::addOption
(
"add",
"value",
"Add a new entry"
);
argList::addBoolOption
(
"remove",
"Remove the entry."
);
argList::addOption
(
"diff",
"dict",
"Write differences with respect to the specified dictionary"
);
argList::addBoolOption
(
"includes",
"List the #include/#includeIfPresent files to standard output"
);
argList::addBoolOption
(
"expand",
"Read the specified dictionary file, expand the macros etc. and write "
"the resulting dictionary to standard output"
);
argList::addBoolOption
(
"disableFunctionEntries",
"Disable expansion of dictionary directives - #include, #codeStream etc"
);
argList args(argc, argv);
const bool listIncludes = args.optionFound("includes");
if (listIncludes)
{
Foam::functionEntries::includeEntry::log = true;
}
const bool disableEntries = args.optionFound("disableFunctionEntries");
if (disableEntries)
{
Info<< "Not expanding variables or dictionary directives"
<< endl;
entry::disableFunctionEntries = true;
}
fileName dictFileName(args[1]);
autoPtr<IFstream> dictFile(new IFstream(dictFileName));
if (!dictFile().good())
{
FatalErrorInFunction
<< "Cannot open file " << dictFileName
<< exit(FatalError, 1);
}
bool changed = false;
// Read but preserve headers
dictionary dict;
dict.read(dictFile(), true);
if (listIncludes)
{
return 0;
}
else if (args.optionFound("expand"))
{
IOobject::writeBanner(Info)
<<"//\n// " << dictFileName << "\n//\n";
dict.write(Info, false);
IOobject::writeDivider(Info);
return 0;
}
// Second dictionary for -diff
dictionary diffDict;
fileName diffFileName;
if (args.optionReadIfPresent("diff", diffFileName))
{
autoPtr<IFstream> diffFile(new IFstream(diffFileName));
if (!diffFile().good())
{
FatalErrorInFunction
<< "Cannot open file " << diffFileName
<< exit(FatalError, 1);
}
// Read but preserve headers
diffDict.read(diffFile(), true);
}
word entryName;
if (args.optionReadIfPresent("entry", entryName))
{
word scopedName(scope(entryName));
string newValue;
if
(
args.optionReadIfPresent("set", newValue)
|| args.optionReadIfPresent("add", newValue)
)
{
bool overwrite = args.optionFound("set");
Pair<word> dAk(dictAndKeyword(scopedName));
IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
entry* ePtr(entry::New(str).ptr());
const dictionary& d(lookupScopedDict(dict, dAk.first()));
if (overwrite)
{
const_cast<dictionary&>(d).set(ePtr);
}
else
{
const_cast<dictionary&>(d).add(ePtr, false);
}
changed = true;
// Print the changed entry
const entry* entPtr = dict.lookupScopedEntryPtr
(
scopedName,
false,
true // Support wildcards
);
if (entPtr)
{
Info<< *entPtr << endl;
}
}
else if (args.optionFound("remove"))
{
// Extract dictionary name and keyword
Pair<word> dAk(dictAndKeyword(scopedName));
const dictionary& d(lookupScopedDict(dict, dAk.first()));
const_cast<dictionary&>(d).remove(dAk.second());
changed = true;
}
else
{
// Optionally remove a second dictionary
if (args.optionFound("diff"))
{
Pair<word> dAk(dictAndKeyword(scopedName));
const dictionary& d(lookupScopedDict(dict, dAk.first()));
const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
const entry* ePtr =
d.lookupEntryPtr(dAk.second(), false, true);
const entry* e2Ptr =
d2.lookupEntryPtr(dAk.second(), false, true);
if (ePtr && e2Ptr)
{
if (*ePtr == *e2Ptr)
{
const_cast<dictionary&>(d).remove(dAk.second());
}
else if (ePtr->isDict() && e2Ptr->isDict())
{
remove
(
const_cast<dictionary&>(ePtr->dict()),
e2Ptr->dict()
);
}
}
}
const entry* entPtr = dict.lookupScopedEntryPtr
(
scopedName,
false,
true // Support wildcards
);
if (entPtr)
{
if (args.optionFound("keywords"))
{
const dictionary& dict = entPtr->dict();
forAllConstIter(dictionary, dict, iter)
{
Info<< iter().keyword() << endl;
}
}
else
{
if (args.optionFound("value"))
{
if (entPtr->isStream())
{
const tokenList& tokens = entPtr->stream();
forAll(tokens, i)
{
Info<< tokens[i] << token::SPACE;
}
Info<< endl;
}
else if (entPtr->isDict())
{
Info<< entPtr->dict();
}
}
else
{
Info<< *entPtr << endl;
}
}
}
else
{
FatalIOErrorInFunction(dictFile)
<< "Cannot find entry " << entryName
<< exit(FatalIOError, 2);
}
}
}
else if (args.optionFound("keywords"))
{
forAllConstIter(dictionary, dict, iter)
{
Info<< iter().keyword() << endl;
}
}
else if (args.optionFound("diff"))
{
remove(dict, diffDict);
dict.write(Info, false);
}
else
{
dict.write(Info, false);
}
if (changed)
{
dictFile.clear();
OFstream os(dictFileName);
IOobject::writeBanner(os);
dict.write(os, false);
IOobject::writeEndDivider(os);
}
return 0;
}
// ************************************************************************* //