All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
foamDictionary.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2016-2020 OpenFOAM Foundation
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  foamDictionary
26 
27 Description
28  Interrogates and manipulates dictionaries.
29 
30  Supports parallel operation for decomposed dictionary files associated with
31  a case. These may be mesh or field files or any other decomposed
32  dictionaries.
33 
34 Usage
35  \b foamDictionary [OPTION] dictionary
36  - \par -parallel
37  Specify case as a parallel job
38 
39  - \par -doc
40  Display the documentation in browser
41 
42  - \par -srcDoc
43  Display the source documentation in browser
44 
45  - \par -help
46  Print the usage
47 
48  - \par -entry <name>
49  Selects an entry
50 
51  - \par -keywords <name>
52  Prints the keywords (of the selected entry or of the top level if
53  no entry was selected
54 
55  - \par -add <value>
56  Adds the entry (should not exist yet)
57 
58  - \par -set <value>
59  Adds or replaces the entry
60 
61  - \par -merge <value>
62  Merges the entry
63 
64  - \par -dict
65  Set, add or merge entry from a dictionary
66 
67  - \par -remove
68  Remove the selected entry
69 
70  - \par -diff <dictionary>
71  Write differences with respect to the specified dictionary
72  (or sub entry if -entry specified)
73 
74  - \par -expand
75  Read the specified dictionary file, expand the macros etc. and write
76  the resulting dictionary to standard output.
77 
78  - \par -includes
79  List the \c #include and \c #includeIfPresent files to standard output
80 
81  Example usage:
82  - Change simulation to run for one timestep only:
83  \verbatim
84  foamDictionary system/controlDict -entry stopAt -set writeNow
85  \endverbatim
86 
87  - Change solver:
88  \verbatim
89  foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
90  \endverbatim
91 
92  - Print bc type:
93  \verbatim
94  foamDictionary 0/U -entry boundaryField.movingWall.type
95  \endverbatim
96 
97  - Change bc parameter:
98  \verbatim
99  foamDictionary 0/U -entry boundaryField.movingWall.value \
100  -set "uniform (2 0 0)"
101  \endverbatim
102 
103  - Change bc parameter in parallel:
104  \verbatim
105  mpirun -np 4 foamDictionary 0.5/U \
106  -entry boundaryField.movingWall.value \
107  -set "uniform (2 0 0)" -parallel
108  \endverbatim
109 
110  - Change whole bc type:
111  \verbatim
112  foamDictionary 0/U -entry boundaryField.movingWall \
113  -set "{type uniformFixedValue; uniformValue (2 0 0);}"
114  \endverbatim
115 
116  - Write the differences with respect to a template dictionary:
117  \verbatim
118  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U
119  \endverbatim
120 
121  - Write the differences in boundaryField with respect to a
122  template dictionary:
123  \verbatim
124  foamDictionary 0/U -diff $FOAM_ETC/templates/closedVolume/0/U \
125  -entry boundaryField
126  \endverbatim
127 
128  - Change patch type:
129  \verbatim
130  foamDictionary constant/polyMesh/boundary \
131  -entry entry0.fixedWalls.type -set patch
132  \endverbatim
133  This uses special parsing of Lists which stores these in the
134  dictionary with keyword 'entryDDD' where DDD is the position
135  in the dictionary (after ignoring the FoamFile entry).
136 
137 \*---------------------------------------------------------------------------*/
138 
139 #include "argList.H"
140 #include "Time.H"
141 #include "localIOdictionary.H"
142 #include "Pair.H"
143 #include "IFstream.H"
144 #include "OFstream.H"
145 #include "includeEntry.H"
146 #include "inputSyntaxEntry.H"
147 
148 using namespace Foam;
149 
150 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
151 
152 //- Read dictionary from file and return
153 // Sets steam to binary mode if specified in the optional header
154 IOstream::streamFormat readDict(dictionary& dict, const fileName& dictFileName)
155 {
157 
158  // Read the first entry and if it is FoamFile set the file format
159  {
160  IFstream dictFile(dictFileName);
161  if (!dictFile().good())
162  {
164  << "Cannot open file " << dictFileName
165  << exit(FatalError, 1);
166  }
167 
168  // Check if the first token in the file is "FoamFile"
169  // to avoid problems if the first entry is a variable or function
170  token firstToken;
171  dictFile.read(firstToken);
172  if (firstToken.isWord() && firstToken.wordToken() == IOobject::foamFile)
173  {
174  dictFile.putBack(firstToken);
175 
176  // Read the first entry from the dictionary
177  autoPtr<entry> firstEntry(entry::New(dictFile()));
178 
179  // If the first entry is the "FoamFile" header
180  // read and set the stream format
181  if
182  (
183  firstEntry->isDict()
184  && firstEntry->keyword() == IOobject::foamFile
185  )
186  {
187  dictFormat = IOstream::formatEnum
188  (
189  firstEntry->dict().lookup("format")
190  );
191  }
192  }
193  }
194 
195  IFstream dictFile(dictFileName, dictFormat);
196 
197  // Read and add the rest of the dictionary entries
198  // preserving the IOobject::foamFile header dictionary if present
199  dict.read(dictFile(), true);
200 
201  return dictFormat;
202 }
203 
204 
205 //- Convert keyword syntax to "dot" if the dictionary is "dot" syntax
206 word scope(const fileName& entryName)
207 {
208  if
209  (
211  && entryName.find('/') != string::npos
212  )
213  {
214  wordList entryNames(entryName.components('/'));
215 
216  word entry(entryNames[0]);
217  for (label i = 1; i < entryNames.size(); i++)
218  {
219  entry += word('.') + entryNames[i];
220  }
221  return entry;
222  }
223  else
224  {
225  return entryName;
226  }
227 }
228 
229 
230 //- Extracts dict name and keyword
231 Pair<word> dictAndKeyword(const word& scopedName)
232 {
233  string::size_type i = scopedName.find_last_of
234  (
236  );
237 
238  if (i != string::npos)
239  {
240  return Pair<word>
241  (
242  scopedName.substr(0, i),
243  scopedName.substr(i+1, string::npos)
244  );
245  }
246  else
247  {
248  return Pair<word>("", scopedName);
249  }
250 }
251 
252 
253 const dictionary& lookupScopedDict
254 (
255  const dictionary& dict,
256  const word& subDictName
257 )
258 {
259  if (subDictName == "")
260  {
261  return dict;
262  }
263  else
264  {
265  const entry* entPtr = dict.lookupScopedEntryPtr
266  (
267  subDictName,
268  false,
269  false
270  );
271  if (!entPtr || !entPtr->isDict())
272  {
274  << "keyword " << subDictName
275  << " is undefined in dictionary "
276  << dict.name() << " or is not a dictionary"
277  << endl
278  << "Valid keywords are " << dict.keys()
279  << exit(FatalIOError);
280  }
281  return entPtr->dict();
282  }
283 }
284 
285 
286 void remove(dictionary& dict, const dictionary& removeDict)
287 {
288  forAllConstIter(dictionary, removeDict, iter)
289  {
290  const entry* entPtr = dict.lookupEntryPtr
291  (
292  iter().keyword(),
293  false,
294  false
295  );
296 
297  if (entPtr)
298  {
299  if (entPtr->isDict())
300  {
301  if (iter().isDict())
302  {
303  remove
304  (
305  const_cast<dictionary&>(entPtr->dict()),
306  iter().dict()
307  );
308 
309  // Check if dictionary is empty
310  if (!entPtr->dict().size())
311  {
312  dict.remove(iter().keyword());
313  }
314  }
315  }
316  else if (!iter().isDict())
317  {
318  if (*entPtr == iter())
319  {
320  dict.remove(iter().keyword());
321  }
322  }
323  }
324  }
325 }
326 
327 
328 int main(int argc, char *argv[])
329 {
330  argList::removeOption("case");
331  writeInfoHeader = false;
332 
333  argList::addNote("manipulates dictionaries");
334 
335  argList::validArgs.append("dictionary file");
336 
337  argList::addBoolOption("keywords", "list keywords");
338  argList::addOption("entry", "name", "report/select the named entry");
340  (
341  "value",
342  "Print entry value"
343  );
345  (
346  "set",
347  "value",
348  "Set entry value or add new entry"
349  );
351  (
352  "add",
353  "value",
354  "Add a new entry"
355  );
357  (
358  "merge",
359  "value",
360  "Merge entry"
361  );
363  (
364  "dict",
365  "Set, add or merge entry from a dictionary."
366  );
368  (
369  "remove",
370  "Remove the entry."
371  );
373  (
374  "diff",
375  "dict",
376  "Write differences with respect to the specified dictionary"
377  );
379  (
380  "includes",
381  "List the #include/#includeIfPresent files to standard output"
382  );
384  (
385  "expand",
386  "Read the specified dictionary file, expand the macros etc. and write "
387  "the resulting dictionary to standard output"
388  );
389 
390  argList args(argc, argv);
391 
392  const bool listIncludes = args.optionFound("includes");
393 
394  if (listIncludes)
395  {
397  }
398 
399  // Do not expand functionEntries except during dictionary expansion
400  // with the -expand option
401  if (!args.optionFound("expand"))
402  {
404  }
405 
406  const fileName dictPath(args[1]);
407 
408  Time* runTimePtr = nullptr;
409  localIOdictionary* localDictPtr = nullptr;
410 
411  dictionary* dictPtr = nullptr;
413 
414  // When running in parallel read the dictionary as a case localIOdictionary
415  // supporting file handlers
416  if (Pstream::parRun())
417  {
418  if (!args.checkRootCase())
419  {
420  FatalError.exit();
421  }
422 
423  runTimePtr = new Time(Time::controlDictName, args);
424 
425  const wordList dictPathComponents(dictPath.components());
426 
427  if (dictPathComponents.size() == 1)
428  {
430  << "File name " << dictPath
431  << " does not contain an instance path needed in parallel"
432  << exit(FatalError, 1);
433  }
434 
435  const word instance = dictPathComponents[0];
436  const fileName dictFileName
437  (
438  SubList<word>(dictPathComponents, dictPathComponents.size() - 1, 1)
439  );
440 
441  scalar time;
442  if (readScalar(instance.c_str(), time))
443  {
444  runTimePtr->setTime(time, 0);
445  }
446 
447  localDictPtr = new localIOdictionary
448  (
449  IOobject
450  (
451  dictFileName,
452  instance,
453  *runTimePtr,
456  false
457  )
458  );
459  }
460  else
461  {
462  dictPtr = new dictionary(dictPath);
463  dictFormat = readDict(*dictPtr, dictPath);
464  }
465 
466  dictionary& dict = localDictPtr ? *localDictPtr : *dictPtr;
467 
468  bool changed = false;
469 
470  if (listIncludes)
471  {
472  return 0;
473  }
474  else if (args.optionFound("expand") && !args.optionFound("entry"))
475  {
477  <<"//\n// " << dictPath << "\n//\n";
478  dict.dictionary::write(Info, false);
480 
481  return 0;
482  }
483 
484 
485  // Second dictionary for -diff
486  fileName diffFileName;
487  dictionary diffDict;
488 
489  if (args.optionReadIfPresent("diff", diffFileName))
490  {
491  readDict(diffDict, diffFileName);
492  }
493 
494 
495  word entryName;
496  if (args.optionReadIfPresent("entry", entryName))
497  {
498  const word scopedName(scope(entryName));
499 
500  string newValue;
501  if
502  (
503  args.optionReadIfPresent("set", newValue)
504  || args.optionReadIfPresent("add", newValue)
505  || args.optionReadIfPresent("merge", newValue)
506  )
507  {
508  const bool overwrite = args.optionFound("set");
509  const bool merge = args.optionFound("merge");
510 
511  Pair<word> dAk(dictAndKeyword(scopedName));
512  const dictionary& d(lookupScopedDict(dict, dAk.first()));
513 
514  entry* ePtr = nullptr;
515 
516  if (args.optionFound("dict"))
517  {
518  const fileName fromDictFileName(newValue);
519  dictionary fromDict;
520  readDict(fromDict, fromDictFileName);
521 
522  const entry* fePtr
523  (
524  fromDict.lookupScopedEntryPtr
525  (
526  scopedName,
527  false,
528  true // Support wildcards
529  )
530  );
531 
532  if (!fePtr)
533  {
535  << "Cannot find entry " << entryName
536  << " in file " << fromDictFileName
537  << exit(FatalError, 1);
538  }
539 
540  ePtr = fePtr->clone().ptr();
541  }
542  else
543  {
544  IStringStream str(string(dAk.second()) + ' ' + newValue + ';');
545  ePtr = entry::New(str).ptr();
546  }
547 
548  if (overwrite)
549  {
550  Info << "New entry " << *ePtr << endl;
551  const_cast<dictionary&>(d).set(ePtr);
552  }
553  else
554  {
555  const_cast<dictionary&>(d).add(ePtr, merge);
556  }
557  changed = true;
558 
559  // Print the changed entry
560  // const entry* entPtr = dict.lookupScopedEntryPtr
561  // (
562  // scopedName,
563  // false,
564  // true // Support wildcards
565  // );
566  // if (entPtr)
567  // {
568  // Info<< *entPtr;
569  // }
570  }
571  else if (args.optionFound("remove"))
572  {
573  // Extract dictionary name and keyword
574  Pair<word> dAk(dictAndKeyword(scopedName));
575 
576  const dictionary& d(lookupScopedDict(dict, dAk.first()));
577  const_cast<dictionary&>(d).remove(dAk.second());
578  changed = true;
579  }
580  else
581  {
582  // Optionally remove a second dictionary
583  if (args.optionFound("diff"))
584  {
585  Pair<word> dAk(dictAndKeyword(scopedName));
586 
587  const dictionary& d(lookupScopedDict(dict, dAk.first()));
588  const dictionary& d2(lookupScopedDict(diffDict, dAk.first()));
589 
590  const entry* ePtr =
591  d.lookupEntryPtr(dAk.second(), false, true);
592  const entry* e2Ptr =
593  d2.lookupEntryPtr(dAk.second(), false, true);
594 
595  if (ePtr && e2Ptr)
596  {
597  if (*ePtr == *e2Ptr)
598  {
599  const_cast<dictionary&>(d).remove(dAk.second());
600  }
601  else if (ePtr->isDict() && e2Ptr->isDict())
602  {
603  remove
604  (
605  const_cast<dictionary&>(ePtr->dict()),
606  e2Ptr->dict()
607  );
608  }
609  }
610  }
611 
612 
613  const entry* entPtr = dict.lookupScopedEntryPtr
614  (
615  scopedName,
616  false,
617  true // Support wildcards
618  );
619 
620  if (entPtr)
621  {
622  if (args.optionFound("keywords"))
623  {
624  const dictionary& dict = entPtr->dict();
625  forAllConstIter(dictionary, dict, iter)
626  {
627  Info<< iter().keyword() << endl;
628  }
629  }
630  else
631  {
632  if (args.optionFound("value"))
633  {
634  if (entPtr->isStream())
635  {
636  const tokenList& tokens = entPtr->stream();
637  forAll(tokens, i)
638  {
639  Info<< tokens[i];
640  if (i < tokens.size() - 1)
641  {
642  Info<< token::SPACE;
643  }
644  }
645  Info<< endl;
646  }
647  else if (entPtr->isDict())
648  {
649  Info<< entPtr->dict();
650  }
651  }
652  else
653  {
654  Info<< *entPtr;
655  }
656  }
657  }
658  else
659  {
661  << "Cannot find entry " << entryName
662  << exit(FatalIOError, 2);
663  }
664  }
665  }
666  else if (args.optionFound("keywords"))
667  {
668  forAllConstIter(dictionary, dict, iter)
669  {
670  Info<< iter().keyword() << endl;
671  }
672  }
673  else if (args.optionFound("diff"))
674  {
675  remove(dict, diffDict);
676  dict.dictionary::write(Info, false);
677  }
678  else
679  {
680  dict.dictionary::write(Info, false);
681  }
682 
683  if (changed)
684  {
685  if (localDictPtr)
686  {
687  localDictPtr->regIOobject::write();
688  }
689  else if (dictPtr)
690  {
691  OFstream os(dictPath, dictFormat);
693  if (dictPtr->found(IOobject::foamFile))
694  {
695  os << IOobject::foamFile;
696  dictPtr->subDict(IOobject::foamFile).write(os);
697  dictPtr->remove(IOobject::foamFile);
698  IOobject::writeDivider(os) << nl;
699  }
700  dictPtr->write(os, false);
702  }
703  }
704 
705  delete dictPtr;
706  delete localDictPtr;
707  delete runTimePtr;
708 
709  return 0;
710 }
711 
712 
713 // ************************************************************************* //
virtual bool isStream() const
Return true if this entry is a stream.
Definition: entry.H:147
void write(Ostream &, const bool subDict=true) const
Write dictionary, normally with sub-dictionary formatting.
Definition: dictionaryIO.C:174
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:1412
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
dictionary dict
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:667
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
bool isWord() const
Definition: tokenI.H:261
static streamFormat formatEnum(const word &)
Return stream format of given format name.
Definition: IOstream.C:39
bool remove(const word &)
Remove an entry specified by keyword.
Definition: dictionary.C:1219
static void removeOption(const word &opt)
Remove option from validOptions and from optionUsage.
Definition: argList.C:168
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
A class for handling file names.
Definition: fileName.H:79
static Stream & writeBanner(Stream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectI.H:65
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
bool writeInfoHeader
Output to file stream.
Definition: OFstream.H:82
const word & wordToken() const
Definition: tokenI.H:266
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:113
A token holds items read from Istream.
Definition: token.H:72
static bool New(dictionary &parentDict, Istream &)
Construct from Istream and insert into dictionary.
Definition: entryIO.C:94
static bool dot()
Return true if the inputSyntax is dot.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:153
bool read(Istream &, const bool keepHeader=false)
Read dictionary from Istream, optionally keeping the header.
Definition: dictionaryIO.C:77
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:204
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:168
const entry * lookupScopedEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:823
wordList components(const char delimiter='/') const
Return path components as wordList.
Definition: fileName.C:302
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:934
localIOdictionary is derived from IOdictionary but excludes parallel master reading.
Info<< "Create engine time\"<< endl;autoPtr< engineTime > runTimePtr(engineTime::New(Time::controlDictName, args.rootPath(), args.caseName()))
A List obtained as a section of another List.
Definition: SubList.H:53
static int disableFunctionEntries
Definition: entry.H:86
const fileName & name() const
Return the dictionary name.
Definition: dictionary.H:111
A class for handling words, derived from string.
Definition: word.H:59
fileName dictPath
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:102
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:128
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:86
virtual void setTime(const Time &)
Reset the time and time-index to those of the given time.
Definition: Time.C:879
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if successful.
Definition: doubleScalar.H:75
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:197
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
static char scopeChar()
Return true if the inputSyntax is slash.
virtual bool isDict() const
Return true if this entry is a dictionary.
Definition: entry.H:156
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
static const char nl
Definition: Ostream.H:260
static constexpr const char * foamFile
Keyword for the FoamFile header sub-dictionary.
Definition: IOobject.H:98
Input from file stream.
Definition: IFstream.H:81
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:1038
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static Stream & writeEndDivider(Stream &os)
Write the standard end file divider.
Definition: IOobjectI.H:123
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:331
Input from memory buffer stream.
Definition: IStringStream.H:49
messageStream Info
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:159
T * first()
Return the first entry.
Definition: UILList.H:109
static bool log
Report which file is included to stdout.
Definition: includeEntry.H:88
virtual ITstream & stream() const =0
Return token stream if this entry is a primitive entry.
Foam::argList args(argc, argv)
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:65
IOerror FatalIOError