changeDictionary.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) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 
27 Application
28  changeDictionary
29 
30 Group
31  grpPreProcessingUtilities
32 
33 Description
34  Utility to change dictionary entries, e.g. can be used to change the patch
35  type in the field and polyMesh/boundary files.
36 
37  Reads dictionaries (fields) and entries to change from a dictionary.
38  E.g. to make the \em movingWall a \em fixedValue for \em p but all other
39  \em Walls a zeroGradient boundary condition, the
40  \c system/changeDictionaryDict would contain the following:
41  \verbatim
42  p // field to change
43  {
44  boundaryField
45  {
46  ".*Wall" // entry to change
47  {
48  type zeroGradient;
49  }
50  movingWall // entry to change
51  {
52  type fixedValue;
53  value uniform 123.45;
54  }
55  }
56  }
57  \endverbatim
58  Replacement entries starting with '~' will remove the entry.
59 
60 Usage
61  \b changeDictionary [OPTION]
62 
63  Options:
64  - \par -subDict
65  Specify the subDict name of the replacements dictionary.
66 
67  - \par -literalRE
68  Do not interpret regular expressions or patchGroups; treat them as any
69  other keyword.
70 
71  - \par -enableFunctionEntries
72  Enable function entries (default: disabled)
73 
74  - \par -disablePatchGroups
75  Disable the default checking for keys being patchGroups
76 
77 \*---------------------------------------------------------------------------*/
78 
79 #include "argList.H"
80 #include "IOobjectList.H"
81 #include "IOPtrList.H"
82 #include "volFields.H"
83 #include "stringListOps.H"
84 #include "timeSelector.H"
85 
86 using namespace Foam;
87 
88 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
89 
90 namespace Foam
91 {
93 }
94 
95 
96 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
97 
98 // Extract groupPatch info from boundary file info
99 HashTable<wordList> extractPatchGroups(const dictionary& boundaryDict)
100 {
101  HashTable<wordList> groupToPatch;
102 
103  for (const entry& dEntry : boundaryDict)
104  {
105  if (!dEntry.isDict())
106  {
107  continue;
108  }
109 
110  const word& patchName = dEntry.keyword();
111  const dictionary& patchDict = dEntry.dict();
112 
113  wordList groupNames;
114  patchDict.readIfPresent("inGroups", groupNames);
115 
116  for (const word& groupName : groupNames)
117  {
118  auto groupIter = groupToPatch.find(groupName);
119  if (groupIter.good())
120  {
121  (*groupIter).append(patchName);
122  }
123  else
124  {
125  groupToPatch.insert(groupName, wordList(one{}, patchName));
126  }
127  }
128  }
129 
130  return groupToPatch;
131 }
132 
133 
134 bool merge
135 (
136  const bool addNonExisting,
137  dictionary&,
138  const dictionary&,
139  const bool,
140  const HashTable<wordList>&
141 );
142 
143 
144 // Add thisEntry to dictionary thisDict.
145 bool addEntry
146 (
147  dictionary& thisDict,
148  entry& thisEntry,
149  const entry& mergeEntry,
150  const bool literalRE,
151  const HashTable<wordList>& shortcuts
152 )
153 {
154  bool changed = false;
155 
156  // Recursively merge sub-dictionaries
157  // TODO: merge without copying
158  if (thisEntry.isDict() && mergeEntry.isDict())
159  {
160  if
161  (
162  merge
163  (
164  true,
165  const_cast<dictionary&>(thisEntry.dict()),
166  mergeEntry.dict(),
167  literalRE,
168  shortcuts
169  )
170  )
171  {
172  changed = true;
173  }
174  }
175  else
176  {
177  // Should use in-place modification instead of adding
178  thisDict.add(mergeEntry.clone(thisDict).ptr(), true);
179  changed = true;
180  }
181 
182  return changed;
183 }
184 
185 
186 // List of indices into thisKeys
187 labelList findMatches
188 (
189  const HashTable<wordList>& shortcuts,
190  const wordList& shortcutNames,
191  const wordList& thisKeys,
192  const keyType& key
193 )
194 {
195  labelList matches;
196 
197  if (key.isPattern())
198  {
199  // Wildcard match
200  matches = findStrings(key, thisKeys);
201  }
202  else if (shortcuts.size())
203  {
204  // See if patchGroups expand to valid thisKeys
205  labelList indices = findStrings(key, shortcutNames);
206 
207  for (const label idx : indices)
208  {
209  const word& name = shortcutNames[idx];
210  const wordList& keys = shortcuts[name];
211  forAll(keys, j)
212  {
213  const label index = thisKeys.find(keys[j]);
214  if (index != -1)
215  {
216  matches.append(index);
217  }
218  }
219  }
220  }
221  return matches;
222 }
223 
224 
225 // Dictionary merging/editing.
226 // literalRE:
227 // - true: behave like dictionary::merge, i.e. add regexps just like
228 // any other key.
229 // - false : interpret wildcard as a rule for items to be matched.
230 bool merge
231 (
232  const bool addNonExisting,
233  dictionary& thisDict,
234  const dictionary& mergeDict,
235  const bool literalRE,
236  const HashTable<wordList>& shortcuts
237 )
238 {
239  const wordList shortcutNames(shortcuts.toc());
240 
241  bool changed = false;
242 
243  // Save current (non-wildcard) keys before adding items.
244  wordHashSet thisKeysSet;
245  {
246  for (const word& k : thisDict.keys(false))
247  {
248  thisKeysSet.insert(k);
249  }
250  }
251 
252  // Pass 1. All literal matches
253 
254  for (const entry& mergeEntry : mergeDict)
255  {
256  const keyType& key = mergeEntry.keyword();
257 
258  if (key[0] == '~')
259  {
260  const word eraseKey = key.substr(1);
261  if (thisDict.remove(eraseKey))
262  {
263  // Mark thisDict entry as having been match for wildcard
264  // handling later on.
265  thisKeysSet.erase(eraseKey);
266  }
267  changed = true;
268  }
269  else if (literalRE || !(key.isPattern() || shortcuts.found(key)))
270  {
271  entry* eptr = thisDict.findEntry(key, keyType::LITERAL);
272 
273  if (eptr)
274  {
275  // Mark thisDict entry as having been match for wildcard
276  // handling later on.
277  thisKeysSet.erase(eptr->keyword());
278 
279  if
280  (
281  addEntry
282  (
283  thisDict,
284  *eptr,
285  mergeEntry,
286  literalRE,
287  shortcuts
288  )
289  )
290  {
291  changed = true;
292  }
293  }
294  else
295  {
296  if (addNonExisting)
297  {
298  // Not found - just add
299  thisDict.add(mergeEntry.clone(thisDict).ptr());
300  changed = true;
301  }
302  else
303  {
304  IOWarningInFunction(mergeDict)
305  << "Ignoring non-existing entry " << key
306  << endl;
307  }
308  }
309  }
310  }
311 
312 
313  // Pass 2. Wildcard or shortcut matches (if any) on any non-match keys.
314 
315  if (!literalRE && thisKeysSet.size())
316  {
317  // Pick up remaining dictionary entries
318  wordList thisKeys(thisKeysSet.toc());
319 
320  for (const entry& mergeEntry : mergeDict)
321  {
322  const keyType& key = mergeEntry.keyword();
323 
324  if (key[0] == '~')
325  {
326  const word eraseKey = key.substr(1);
327 
328  // List of indices into thisKeys
329  labelList matches
330  (
331  findMatches
332  (
333  shortcuts,
334  shortcutNames,
335  thisKeys,
336  eraseKey
337  )
338  );
339 
340  // Remove all matches
341  for (const label matchi : matches)
342  {
343  const word& k = thisKeys[matchi];
344  thisKeysSet.erase(k);
345  }
346  changed = true;
347  }
348  else
349  {
350  // List of indices into thisKeys
351  labelList matches
352  (
353  findMatches
354  (
355  shortcuts,
356  shortcutNames,
357  thisKeys,
358  key
359  )
360  );
361 
362  // Add all matches
363  for (const label matchi : matches)
364  {
365  const word& k = thisKeys[matchi];
366 
367  entry* eptr = thisDict.findEntry(k, keyType::LITERAL);
368 
369  if
370  (
371  addEntry
372  (
373  thisDict,
374  *eptr,
375  mergeEntry,
376  literalRE,
377  HashTable<wordList>(0) // no shortcuts
378  // at deeper levels
379  )
380  )
381  {
382  changed = true;
383  }
384  }
385  }
386  }
387  }
388 
389  return changed;
390 }
391 
392 
393 
394 int main(int argc, char *argv[])
395 {
397  (
398  "Utility to change dictionary entries"
399  " (such as the patch type for fields and polyMesh/boundary files)."
400  );
401 
402  argList::addOption("dict", "file", "Alternative changeDictionaryDict");
403 
405  (
406  "subDict",
407  "name",
408  "Specify the subDict name of the replacements dictionary"
409  );
411  (
412  "instance",
413  "name",
414  "Override instance setting (default is the time name)"
415  );
416 
417  // Add explicit time option
419 
421  (
422  "literalRE",
423  "Treat regular expressions literally (i.e., as a keyword)"
424  );
426  (
427  "enableFunctionEntries",
428  "Enable expansion of dictionary directives - #include, #codeStream etc"
429  );
431  (
432  "disablePatchGroups",
433  "Disable matching keys to patch groups"
434  );
435 
436  #include "addRegionOption.H"
437 
438  #include "setRootCase.H"
439  #include "createTime.H"
440 
441  // Optionally override controlDict time with -time options
443  if (times.size() < 1)
444  {
446  << "No times selected." << exit(FatalError);
447  }
448  forAll(times, timei)
449  {
450  word instance;
451  if (args.readIfPresent("instance", instance))
452  {
453  if (times.size() > 1)
454  {
456  << "Multiple times selected with 'instance' option"
457  << exit(FatalError);
458  }
459  }
460  else
461  {
462  runTime.setTime(times[timei], timei);
463  instance = runTime.timeName();
464  }
465 
466  #include "createNamedMesh.H"
467 
468  const bool literalRE = args.found("literalRE");
469  if (literalRE)
470  {
471  Info<< "Not interpreting any regular expressions (RE)"
472  << " in the changeDictionaryDict." << endl
473  << "Instead they are handled as any other entry, i.e. added if"
474  << " not present." << endl;
475  }
476 
477  const bool enableEntries = args.found("enableFunctionEntries");
478  if (enableEntries)
479  {
480  Info<< "Allowing dictionary preprocessing (#include, #codeStream)."
481  << endl;
482  }
483 
484  const int oldFlag = entry::disableFunctionEntries;
485  if (!enableEntries)
486  {
487  // By default disable dictionary expansion for fields
489  }
490 
491 
492  const bool disablePatchGroups = args.found("disablePatchGroups");
493  if (disablePatchGroups)
494  {
495  Info<< "Not interpreting any keys in the changeDictionary"
496  << " as patchGroups"
497  << endl;
498  }
499 
500 
501  // Make sure we do not use the master-only reading since we read
502  // fields (different per processor) as dictionaries.
504 
505 
506  // Get the replacement rules from a dictionary
507 
508  const word dictName("changeDictionaryDict");
509  #include "setSystemMeshDictionaryIO.H"
511 
512  const dictionary* replaceDictsPtr = &dict;
513 
514  if (args.found("subDict"))
515  {
516  replaceDictsPtr = &dict.subDict(args["subDict"]);
517  }
518 
519  const dictionary& replaceDicts = *replaceDictsPtr;
520 
521  Info<< "Read dictionary " << dict.name()
522  << " with replacements for dictionaries "
523  << replaceDicts.toc() << endl;
524 
525 
526 
527  // Always read boundary to get patch groups
528  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
529 
530  Info<< "Reading polyMesh/boundary file to extract patch names"
531  << endl;
532 
533  // Read PtrList of dictionary as dictionary.
534  const word oldTypeName = IOPtrList<entry>::typeName;
536  IOPtrList<entry> dictList
537  (
538  IOobject
539  (
540  "boundary",
542  (
544  "boundary",
546  ),
548  mesh,
552  )
553  );
554  const_cast<word&>(IOPtrList<entry>::typeName) = oldTypeName;
555 
556  // Fake type back to what was in field
557  const_cast<word&>(dictList.type()) = dictList.headerClassName();
558 
559  // Temporary convert to dictionary
560  dictionary fieldDict;
561  for (const entry& e : dictList)
562  {
563  if (e.isDict())
564  {
565  fieldDict.add(e.keyword(), e.dict());
566  }
567  }
568 
569  if (dictList.size())
570  {
571  Info<< "Loaded dictionary " << dictList.name()
572  << " with entries " << fieldDict.toc() << endl;
573  }
574 
575  // Extract any patchGroups information (= shortcut for set of
576  // patches)
577  HashTable<wordList> patchGroups;
578  if (!disablePatchGroups)
579  {
580  patchGroups = extractPatchGroups(fieldDict);
581  if (patchGroups.size())
582  {
583  Info<< "Extracted patch groups:" << endl;
584  wordList groups(patchGroups.sortedToc());
585  forAll(groups, i)
586  {
587  Info<< " group " << groups[i] << " with patches "
588  << patchGroups[groups[i]] << endl;
589  }
590  }
591  }
592 
593 
594  // Every replacement is a dictionary name and a keyword in this
595 
596  for (const entry& replaceEntry : replaceDicts)
597  {
598  if (!replaceEntry.isDict())
599  {
600  // Could also warn
601  continue;
602  }
603 
604  const word& fieldName = replaceEntry.keyword();
605  const dictionary& replaceDict = replaceEntry.dict();
606 
607  Info<< "Replacing entries in dictionary " << fieldName << endl;
608 
609  // Handle 'boundary' specially:
610  // - is PtrList of dictionaries
611  // - is in polyMesh/
612  if (fieldName == "boundary")
613  {
614  Info<< "Special handling of " << fieldName
615  << " as polyMesh/boundary file." << endl;
616 
617  // Merge the replacements in. Do not add non-existing entries.
618  Info<< "Merging entries from " << replaceDict.toc() << endl;
619  merge(false, fieldDict, replaceDict, literalRE, patchGroups);
620 
621  Info<< "fieldDict:" << fieldDict << endl;
622 
623  // Convert back into dictList
624  wordList doneKeys(dictList.size());
625 
626  label nEntries = fieldDict.size();
627  nEntries = 0;
628 
629  forAll(dictList, i)
630  {
631  doneKeys[i] = dictList[i].keyword();
632 
633  const entry* ePtr = fieldDict.findEntry
634  (
635  doneKeys[i],
637  );
638  // Check that it hasn't been removed from fieldDict
639  if (ePtr)
640  {
641  dictList.set(nEntries++, ePtr->clone());
642  fieldDict.remove(doneKeys[i]);
643  }
644  }
645 
646  // Add remaining entries
647  for (const entry& e : fieldDict)
648  {
649  dictList.set(nEntries++, e.clone());
650  }
651  dictList.setSize(nEntries);
652 
653  Info<< "Writing modified " << fieldName << endl;
654  dictList.writeObject
655  (
657  true
658  );
659  }
660  else
661  {
662  // Read dictionary
663  // Note: disable class type checking so we can load field
664  Info<< "Loading dictionary " << fieldName << endl;
665  const word oldTypeName = localIOdictionary::typeName;
666  const_cast<word&>(localIOdictionary::typeName) = word::null;
667 
668  IOobject fieldHeader
669  (
670  fieldName,
671  instance,
672  mesh,
676  );
677 
678  if (fieldHeader.typeHeaderOk<localIOdictionary>(false))
679  {
680  //IOdictionary fieldDict(fieldHeader);
681  //- dictionaries to-be-changed are either boundary
682  // or field dictionary. Both are processor-local.
683  localIOdictionary fieldDict(fieldHeader);
684 
685  const_cast<word&>(localIOdictionary::typeName) =
686  oldTypeName;
687 
688  // Fake type back to what was in field
689  const_cast<word&>(fieldDict.type()) =
690  fieldDict.headerClassName();
691 
692  Info<< "Loaded dictionary " << fieldName
693  << " with entries " << fieldDict.toc() << endl;
694 
695  // Merge the replacements in (allow adding)
696  Info<< "Merging entries from " << replaceDict.toc() << endl;
697  merge(true, fieldDict, replaceDict, literalRE, patchGroups);
698 
699  Info<< "Writing modified fieldDict " << fieldName << endl;
700  fieldDict.regIOobject::write();
701  }
702  else
703  {
705  << "Requested field to change " << fieldName
706  << " does not exist in " << fieldHeader.path() << endl;
707  }
708  }
709 
711  }
712  }
713 
714  Info<< "\nEnd\n" << endl;
715 
716  return 0;
717 }
718 
719 
720 // ************************************************************************* //
A class for handling keywords in dictionaries.
Definition: keyType.H:66
virtual autoPtr< entry > clone(const dictionary &parentDict) const =0
Construct on freestore as copy with reference to the.
dictionary dict
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
word findInstance(const fileName &dir, const word &name=word::null, IOobjectOption::readOption rOpt=IOobjectOption::MUST_READ, const word &stopInstance=word::null) const
Return time instance (location) of dir that contains the file name (eg, used in reading mesh data)...
Definition: Time.C:787
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:500
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:204
bool found(const Key &key) const
Same as contains()
Definition: HashTable.H:1333
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:842
const word dictName("faMeshDefinition")
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:402
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
Required Variables.
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:374
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:637
A simple container for options an IOstream can normally have.
Operations on lists of strings.
label k
Boltzmann constant.
Ignore writing from objectRegistry::writeObject()
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:227
const fileName & name() const noexcept
The dictionary name.
Definition: dictionaryI.H:41
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:453
wordList toc() const
Return the table of contents.
Definition: dictionary.C:599
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
bool remove(const word &keyword)
Remove an entry specified by keyword.
localIOdictionary is derived from IOdictionary but excludes parallel master reading.
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:152
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:331
Foam::word regionName(Foam::polyMesh::defaultRegion)
static int disableFunctionEntries
Enable or disable use of function entries and variable expansions.
Definition: entry.H:139
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
const keyType & keyword() const noexcept
Return keyword.
Definition: entry.H:231
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
A class for handling words, derived from Foam::string.
Definition: word.H:63
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: HashTableI.H:86
Reading is optional [identical to LAZY_READ].
static const word null
An empty word.
Definition: word.H:84
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:385
static instantList selectIfPresent(Time &runTime, const argList &args)
If any time option provided return the set of times (as select0) otherwise return just the current ti...
Definition: timeSelector.C:265
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:997
String literal.
Definition: keyType.H:82
static word timeName(const scalar t, const int precision=precision_)
Return time name of given scalar time formatted with the given precision.
Definition: Time.C:770
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
defineTemplateTypeNameAndDebug(faScalarMatrix, 0)
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:326
IOstreamOption::streamFormat writeFormat() const noexcept
The write stream format.
Definition: Time.H:491
List< keyType > keys(bool patterns=false) const
Return the list of available keys or patterns.
Definition: dictionary.C:619
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition: HashTable.C:473
List< word > wordList
List of word.
Definition: fileName.H:58
A PtrList of objects of type <T> with automated input and output.
Definition: IOPtrList.H:49
#define WarningInFunction
Report a warning using Foam::Warning.
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
List< Key > sortedToc() const
The table of contents (the keys) in sorted order.
Definition: HashTable.C:130
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:80
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:287
IOobject dictIO
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
bool readIfPresent(const word &optName, T &val) const
Read a value from the named option if present.
Definition: argListI.H:316
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:115
Foam::argList args(argc, argv)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:171
labelList findStrings(const regExp &matcher, const UList< StringType > &input, const bool invert=false)
Return list indices for strings matching the regular expression.
Definition: stringListOps.H:92
Regular expression.
Definition: keyType.H:83
Do not request registration (bool: false)
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
A class representing the concept of 1 (one) that can be used to avoid manipulating objects known to b...
Definition: one.H:56