foamDictionary.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2016-2017 OpenFOAM Foundation
9 Copyright (C) 2017-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27Application
28 foamDictionary
29
30Description
31 Interrogate and manipulate dictionaries.
32
33Usage
34 \b foamDictionary [OPTION] dictionary
35
36 - \par -entry <name>
37 Selects an entry
38
39 - \par -keywords
40 Prints the keywords (of the selected entry or of the top level if
41 no entry was selected
42
43 - \par -add <value>
44 Adds the entry (should not exist yet)
45
46 - \par -set <value>
47 Adds or replaces the entry
48
49 - \par -remove
50 Remove the selected entry
51
52 - \par -diff <dictionary>
53 Write differences with respect to the specified dictionary
54 (or sub entry if -entry specified)
55
56 - \par -diff-etc <dictionary>
57 Write differences with respect to the specified dictionary
58 (or sub entry if -entry specified)
59
60 - \par -expand
61 Read the specified dictionary file, expand the macros etc. and write
62 the resulting dictionary to standard output.
63
64 - \par -includes
65 List the \c \#include and \c \#sinclude files to standard output
66
67 - \par -disableFunctionEntries
68 Do not expand macros or directives (\#include etc)
69
70 - \par -precision int
71 Set default write precision for IOstreams
72
73 Example usage:
74 - Change simulation to run for one timestep only:
75 \verbatim
76 foamDictionary system/controlDict -entry stopAt -set writeNow
77 \endverbatim
78
79 - Change solver:
80 \verbatim
81 foamDictionary system/fvSolution -entry solvers.p.solver -set PCG
82 \endverbatim
83
84 - Print bc type:
85 \verbatim
86 foamDictionary 0/U -entry boundaryField.movingWall.type
87 \endverbatim
88
89 - Change bc parameter:
90 \verbatim
91 foamDictionary 0/U -entry boundaryField.movingWall.value \
92 -set "uniform (2 0 0)"
93 \endverbatim
94
95 - Change whole bc type:
96 \verbatim
97 foamDictionary 0/U -entry boundaryField.movingWall \
98 -set "{type uniformFixedValue; uniformValue (2 0 0);}"
99 \endverbatim
100
101 - Write the differences with respect to a template dictionary:
102 \verbatim
103 foamDictionary 0/U -diff-etc templates/closedVolume/0/U
104 \endverbatim
105
106 - Write the differences in boundaryField with respect to a
107 template dictionary:
108 \verbatim
109 foamDictionary 0/U -diff-etc templates/closedVolume/0/U \
110 -entry boundaryField
111 \endverbatim
112
113 - Change patch type:
114 \verbatim
115 foamDictionary constant/polyMesh/boundary \
116 -entry entry0.fixedWalls.type -set patch
117 \endverbatim
118 This uses special parsing of Lists which stores these in the
119 dictionary with keyword 'entryDDD' where DDD is the position
120 in the dictionary (after ignoring the FoamFile entry).
121
122 Notes:
123 - the use of '.' as the scoping symbol might conflict with
124 e.g. file extensions ('.' is not really considered
125 to be a valid word character). Instead use the '/' as a scoping
126 character e.g.
127 foamDictionary system/snappyHexMeshDict \
128 -entry /geometry/motorBike.obj -remove
129
130\*---------------------------------------------------------------------------*/
131
132#include "argList.H"
133#include "profiling.H"
134#include "Time.H"
135#include "Fstream.H"
136#include "etcFiles.H"
137#include "includeEntry.H"
138
139using namespace Foam;
140
141// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
142
143//- Convert older ':' scope syntax to newer '.' scope syntax,
144// but leave anything with '/' delimiters untouched
145bool upgradeScope(word& entryName)
146{
147 if
148 (
149 entryName.find('/') == string::npos
150 && entryName.find(':') != string::npos
151 )
152 {
153 const wordList names(fileName(entryName).components(':'));
154
155 entryName.resize(0);
156
157 for (const word& name : names)
158 {
159 if (entryName.size()) entryName.append(".");
160
161 entryName.append(name);
162 }
163
164 return true;
165 }
166
167 // Nothing changed
168 return false;
169}
170
171
172//- Split into dictionary name and the entry name
173class dictAndKeyword
174{
175 word dict_;
176 word key_;
177
178public:
179
180 dictAndKeyword(const word& scopedName)
181 {
182 auto i = scopedName.rfind('/');
183 if (i == string::npos)
184 {
185 i = scopedName.rfind('.');
186 }
187
188 if (i != string::npos)
189 {
190 dict_ = scopedName.substr(0, i);
191 key_ = scopedName.substr(i+1);
192 }
193 else
194 {
195 key_ = scopedName;
196 }
197 }
198
199 inline const word& dict() const
200 {
201 return dict_;
202 }
203
204 inline const word& key() const
205 {
206 return key_;
207 }
208};
209
210
211const dictionary& lookupScopedDict
212(
213 const dictionary& dict,
214 const word& subDictName
215)
216{
217 if (subDictName.empty())
218 {
219 return dict;
220 }
221
222 const entry* eptr = dict.findScoped(subDictName, keyType::LITERAL);
223
224 if (!eptr || !eptr->isDict())
225 {
227 << "'" << subDictName << "' not found in dictionary "
228 << dict.name() << " or is not a dictionary" << nl
229 << "Known entries are " << dict.keys()
230 << exit(FatalIOError);
231 }
232
233 return eptr->dict();
234}
235
236
237void removeDict(dictionary& dict, const dictionary& dictToRemove)
238{
239 for (const entry& refEntry : dictToRemove)
240 {
241 auto finder = dict.search(refEntry.keyword(), keyType::LITERAL);
242
243 bool purge = false;
244
245 if (finder.isDict())
246 {
247 if (refEntry.isDict())
248 {
249 removeDict(finder.dict(), refEntry.dict());
250
251 // Purge if dictionary is empty
252 purge = finder.dict().empty();
253 }
254 }
255 else if (finder.found() && !refEntry.isDict())
256 {
257 // Purge if entries match
258 purge = (finder.ref() == refEntry);
259 }
260
261 if (purge)
262 {
263 dict.remove(refEntry.keyword());
264 }
265 }
266}
267
268
269int main(int argc, char *argv[])
270{
271 argList::addNote
272 (
273 "Interrogate and manipulate dictionaries"
274 );
275
276 argList::noBanner();
277 argList::noJobInfo();
278 argList::addArgument("dict", "The dictionary file to process");
279 argList::addBoolOption("keywords", "List keywords");
280 argList::addOption("entry", "name", "Report/select the named entry");
281 argList::addBoolOption
282 (
283 "value",
284 "Print entry value"
285 );
286 argList::addOption
287 (
288 "set",
289 "value",
290 "Set entry value or add new entry"
291 );
292 argList::addOption
293 (
294 "add",
295 "value",
296 "Add a new entry"
297 );
298 argList::addBoolOption
299 (
300 "remove",
301 "Remove the entry"
302 );
303 argList::addOption
304 (
305 "diff",
306 "dict",
307 "Write differences with respect to the specified dictionary"
308 );
309 argList::addOption
310 (
311 "diff-etc",
312 "dict",
313 "As per -diff, but locate the file as per foamEtcFile"
314 );
315 argList::addOptionCompat("diff-etc", {"diffEtc", 1712});
316 argList::addOption
317 (
318 "precision",
319 "int",
320 "Set default write precision for IOstreams"
321 );
322
323 argList::addBoolOption
324 (
325 "includes",
326 "List the #include/#sinclude files to standard output"
327 );
328 argList::addBoolOption
329 (
330 "expand",
331 "Read the specified dictionary file, expand the macros etc. and write "
332 "the resulting dictionary to standard output"
333 );
334 argList::addBoolOption
335 (
336 "disableFunctionEntries",
337 "Disable expansion of dictionary directives - #include, #codeStream etc"
338 );
339 profiling::disable(); // Disable profiling (and its output)
340
341 argList args(argc, argv);
342
343 const bool listIncludes = args.found("includes");
344
345 if (listIncludes)
346 {
348 }
349
350 const bool disableEntries = args.found("disableFunctionEntries");
351 if (disableEntries)
352 {
353 // Report on stderr (once) to avoid polluting the output
354 if (Pstream::master())
355 {
356 Serr<< "Not expanding variables or dictionary directives" << endl;
357 }
358 entry::disableFunctionEntries = true;
359 }
360
361 // Set the default output precision
362 {
363 const unsigned prec = args.getOrDefault<unsigned>("precision", 0u);
364 if (prec)
365 {
366 // if (Pstream::master())
367 // {
368 // Serr<< "Output write precision set to " << prec << endl;
369 // }
370
371 IOstream::defaultPrecision(prec);
372 Sout.precision(prec);
373 }
374 }
375
376 const auto dictFileName = args.get<fileName>(1);
377
378 autoPtr<IFstream> dictFile(new IFstream(dictFileName));
379 if (!dictFile().good())
380 {
382 << "Cannot open file " << dictFileName
383 << exit(FatalError, 1);
384 }
385
386
387 bool changed = false;
388
389 // Read but preserve headers
390 dictionary dict(dictFile(), true);
391
392 if (listIncludes)
393 {
394 return 0;
395 }
396 else if (args.found("expand"))
397 {
398 IOobject::writeBanner(Info)
399 <<"//\n// " << dictFileName << "\n//\n";
400 dict.write(Info, false);
401 IOobject::writeDivider(Info);
402
403 return 0;
404 }
405
406
407 // Has "diff" or "diff-etc"
408 bool optDiff = false;
409
410 // Reference dictionary for -diff / -diff-etc
411 dictionary diffDict;
412 {
413 fileName diffFileName;
414 if (args.readIfPresent("diff", diffFileName))
415 {
416 IFstream diffFile(diffFileName);
417 if (!diffFile.good())
418 {
420 << "Cannot open file " << diffFileName
421 << exit(FatalError, 1);
422 }
423
424 // Read but preserve headers
425 diffDict.read(diffFile, true);
426 optDiff = true;
427 }
428 else if (args.readIfPresent("diff-etc", diffFileName))
429 {
430 fileName foundName = findEtcFile(diffFileName);
431 if (foundName.empty())
432 {
434 << "Cannot find etcFile " << diffFileName
435 << exit(FatalError, 1);
436 }
437
438 IFstream diffFile(foundName);
439 if (!diffFile.good())
440 {
442 << "Cannot open file " << foundName
443 << exit(FatalError, 1);
444 }
445
446 // Read but preserve headers
447 diffDict.read(diffFile, true);
448 optDiff = true;
449 }
450 }
451
452 word scopedName; // Actually fileName, since it can contain '/' scoping
453 if (args.readIfPresent("entry", scopedName))
454 {
455 upgradeScope(scopedName);
456
457 string newValue;
458 if
459 (
460 args.readIfPresent("set", newValue)
461 || args.readIfPresent("add", newValue)
462 )
463 {
464 const bool overwrite = args.found("set");
465
466 // Dictionary name and keyword
467 const dictAndKeyword dAk(scopedName);
468
469 // The context for the action
470 const dictionary& d(lookupScopedDict(dict, dAk.dict()));
471
472 // Create a new entry
473 IStringStream str(string(dAk.key()) + ' ' + newValue + ';');
474 entry* ePtr(entry::New(str).ptr());
475
476 if (overwrite)
477 {
478 const_cast<dictionary&>(d).set(ePtr);
479 }
480 else
481 {
482 const_cast<dictionary&>(d).add(ePtr, false);
483 }
484 changed = true;
485
486 // Print the changed entry
487 const auto finder = dict.csearchScoped(scopedName, keyType::REGEX);
488
489 if (finder.found())
490 {
491 Info<< finder.ref();
492 }
493 }
494 else if (args.found("remove"))
495 {
496 // Dictionary name and keyword
497 const dictAndKeyword dAk(scopedName);
498
499 // The context for the action
500 const dictionary& d(lookupScopedDict(dict, dAk.dict()));
501
502 const_cast<dictionary&>(d).remove(dAk.key());
503 changed = true;
504 }
505 else
506 {
507 // Optionally remove a second dictionary
508 if (optDiff)
509 {
510 // Dictionary name and keyword
511 const dictAndKeyword dAk(scopedName);
512
513 const dictionary& d1(lookupScopedDict(dict, dAk.dict()));
514 const dictionary& d2(lookupScopedDict(diffDict, dAk.dict()));
515
516 const entry* e1Ptr = d1.findEntry(dAk.key(), keyType::REGEX);
517 const entry* e2Ptr = d2.findEntry(dAk.key(), keyType::REGEX);
518
519 if (e1Ptr && e2Ptr)
520 {
521 if (*e1Ptr == *e2Ptr)
522 {
523 const_cast<dictionary&>(d1).remove(dAk.key());
524 }
525 else if (e1Ptr->isDict() && e2Ptr->isDict())
526 {
527 removeDict
528 (
529 const_cast<dictionary&>(e1Ptr->dict()),
530 e2Ptr->dict()
531 );
532 }
533 }
534 }
535
536 const auto finder = dict.csearchScoped(scopedName, keyType::REGEX);
537
538 if (!finder.found())
539 {
540 FatalIOErrorInFunction(dictFile())
541 << "Cannot find entry " << scopedName
542 << exit(FatalIOError, 2);
543 }
544 else if (args.found("keywords"))
545 {
546 for (const entry& e : finder.dict())
547 {
548 Info<< e.keyword() << endl;
549 }
550 }
551 else if (args.found("value"))
552 {
553 if (finder.isDict())
554 {
555 Info<< finder.dict();
556 }
557 else if (finder.ref().isStream())
558 {
559 const tokenList& tokens = finder.ref().stream();
560 forAll(tokens, i)
561 {
562 Info<< tokens[i];
563 if (i < tokens.size() - 1)
564 {
565 Info<< token::SPACE;
566 }
567 }
568 Info<< endl;
569 }
570 }
571 else
572 {
573 Info<< finder.ref();
574 }
575 }
576 }
577 else if (args.found("keywords"))
578 {
579 for (const entry& e : dict)
580 {
581 Info<< e.keyword() << endl;
582 }
583 }
584 else if (optDiff)
585 {
586 removeDict(dict, diffDict);
587 dict.write(Info, false);
588 }
589 else
590 {
591 dict.write(Info, false);
592 }
593
594 if (changed)
595 {
596 dictFile.clear();
597 OFstream os(dictFileName);
598 IOobject::writeBanner(os);
599 IOobject::writeDivider(os);
600 dict.write(os, false);
601 IOobject::writeEndDivider(os);
602 }
603
604 return 0;
605}
606
607
608// ************************************************************************* //
Input from file stream, using an ISstream.
Definition: IFstream.H:57
Input from string buffer, using a ISstream. Always UNCOMPRESSED.
Definition: StringStream.H:112
Output to file stream, using an OSstream.
Definition: OFstream.H:57
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:326
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:124
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:278
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:178
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:323
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:307
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
bool read(Istream &is)
Read dictionary from Istream. Discards the header.
Definition: dictionaryIO.C:141
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:70
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:233
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
A class for handling file names.
Definition: fileName.H:76
Computes the natural logarithm of an input volScalarField.
Definition: log.H:230
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:473
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Functions to search 'etc' directories for configuration files etc.
OBJstream os(runTime.globalPath()/outputName)
void set(List< bool > &bools, const labelUList &locations)
Set the listed locations (assign 'true').
Definition: BitOps.C:38
List< word > names(const UPtrList< T > &list, const UnaryMatchPredicate &matcher)
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:108
Namespace for OpenFOAM.
messageStream Info
Information stream (stdout output on master, null elsewhere)
fileName findEtcFile(const fileName &name, const bool mandatory=false, unsigned short location=0777)
Search for a single FILE within the etc directories.
Definition: etcFiles.C:446
OSstream Sout
OSstream wrapped stdout (std::cout)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
OSstream Serr
OSstream wrapped stderr (std::cerr)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dict add("bounds", meshBb)
dictionary dict
Foam::argList args(argc, argv)
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333