argList.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-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2023 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 \*---------------------------------------------------------------------------*/
28 
29 #include "argList.H"
30 #include "OSspecific.H"
31 #include "Switch.H"
32 #include "clock.H"
33 #include "dictionary.H"
34 #include "IOobject.H"
35 #include "JobInfo.H"
36 #include "labelList.H"
37 #include "IOobject.H"
38 #include "dynamicCode.H"
39 #include "simpleObjectRegistry.H"
40 #include "sigFpe.H"
41 #include "sigInt.H"
42 #include "sigQuit.H"
43 #include "sigSegv.H"
44 #include "foamVersion.H"
45 #include "stringOps.H"
46 #include "CStringList.H"
47 #include "stringListOps.H"
48 #include "fileOperation.H"
50 
51 #include <cctype>
52 
53 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
54 
55 bool Foam::argList::argsMandatory_ = true;
56 bool Foam::argList::checkProcessorDirectories_ = true;
57 bool Foam::argList::parallelThreads_ = false;
58 
70 
73 
74 Foam::argList::initValidTables::initValidTables()
75 {
76  argList::addOption
77  (
78  "case",
79  "dir",
80  "Case directory (instead of current directory)"
81  );
82  argList::addOption
83  (
84  "lib",
85  "name",
86  "Additional library or library list to load.\n"
87  "[Can be used multiple times]",
88  true // advanced option
89  );
90  argList::addBoolOption
91  (
92  "no-libs",
93  "Disable use of the controlDict 'libs' entry",
94  true // advanced option
95  );
96 
97  argList::addOption
98  (
99  "debug-switch",
100  "name=val",
101  "Set named DebugSwitch (default value: 1).\n"
102  "[Can be used multiple times]",
103  true // advanced option
104  );
105 
106  argList::addOption
107  (
108  "info-switch",
109  "name=val",
110  "Set named InfoSwitch (default value: 1).\n"
111  "[Can be used multiple times]",
112  true // advanced option
113  );
114 
115  argList::addOption
116  (
117  "opt-switch",
118  "name=val",
119  "Set named OptimisationSwitch (default value: 1).\n"
120  "[Can be used multiple times]",
121  true // advanced option
122  );
123 
124  argList::addBoolOption("parallel", "Run in parallel");
125  validParOptions.set("parallel", "");
126 
127  argList::addBoolOption
128  (
129  "mpi-threads",
130  "Request use of MPI threads",
131  true // advanced option
132  );
133 
134  argList::addOption
135  (
136  "roots",
137  "(dir1 .. dirN)",
138  "Subprocess root directories for distributed running",
139  true // advanced option
140  );
141  validParOptions.set
142  (
143  "roots",
144  "(dir1 .. dirN)"
145  );
146 
147  argList::addOption
148  (
149  "decomposeParDict",
150  "file",
151  "Alternative decomposePar dictionary file"
152  );
153  argList::addOption
154  (
155  "hostRoots",
156  "((host1 dir1) .. (hostN dirN))",
157  "Per-subprocess root directories for distributed running."
158  " The host specification can be a regex.",
159  true // advanced option
160  );
161  validParOptions.set
162  (
163  "hostRoots",
164  "((host1 dir1) .. (hostN dirN))"
165  );
166 
167  argList::addBoolOption
168  (
169  "noFunctionObjects",
170  "Do not execute function objects",
171  true // advanced option
172  );
173 
174  argList::addOption
175  (
176  "fileHandler",
177  "handler",
178  "Override the file handler type",
179  true // advanced option
180  );
181 
182  argList::addOption
183  (
184  "world",
185  "name",
186  "Name of the local world for parallel communication",
187  true // advanced option
188  );
189  validParOptions.set
190  (
191  "world",
192  "name"
193  );
194 
195 
196  // Some standard option aliases (with or without version warnings)
197 // argList::addOptionCompat
198 // (
199 // "noFunctionObjects", {"no-function-objects", 0}
200 // );
201 
202  Pstream::addValidParOptions(validParOptions);
203 }
204 
205 Foam::argList::initValidTables dummyInitValidTables;
206 
207 
208 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
209 
210 namespace Foam
211 {
213 // Counted per machine name
214 // Does not include any sorting since we wish to know the ordering according to
215 // mpi rank.
216 //
217 // Always include the master too.
218 // This provides a better overview of the subscription
219 static void printHostsSubscription(const UList<string>& hostProcs)
220 {
221  Info<< "Hosts :\n(" << nl;
222 
223  std::string prev = Foam::hostName();
224  int count = 1;
225 
226  for (const auto& str : hostProcs)
227  {
228  std::string curr(str.substr(0, str.rfind('.')));
229 
230  if (prev != curr)
231  {
232  if (count)
233  {
234  // Finish previous
235  Info<< " (" << prev.c_str() << ' ' << count << ')' << nl;
236  count = 0;
237  }
238 
239  prev = std::move(curr);
240  }
241  ++count;
242  }
243 
244  if (count)
245  {
246  // Finished last one
247  Info<< " (" << prev.c_str() << ' ' << count << ')' << nl;
248  }
249 
250  Info<< ')' << nl;
251 }
252 
253 
254 static bool printRootsSubscription
255 (
256  const UList<string>& hostProcs,
257  const UList<fileName>& roots
258 )
259 {
260  if (hostProcs.size() == roots.size()+1)
261  {
262  // Sort roots according to hostProc
263  DynamicList<string> sortedProcs;
264  DynamicList<label> sortedRoots;
265 
266  forAll(roots, i)
267  {
268  const fileName& root = roots[i];
269  const string& host = hostProcs[i+1];
270  const label index = sortedProcs.find(host);
271 
272  if (index == -1)
273  {
274  sortedProcs.append(host);
275  sortedRoots.append(i);
276  }
277  else if (roots[sortedRoots[index]] != root)
278  {
279  // Not properly sorted...
280  return false;
281  }
282  }
283 
284  Info<< "Roots :\n(" << nl;
285  forAll(sortedProcs, i)
286  {
287  Info<< " (" << sortedProcs[i].c_str() << ' '
288  << roots[sortedRoots[i]] << ')' << nl;
289  }
290  Info<< ')' << nl;
291 
292  return true;
293  }
294 
295  return false;
296 }
297 
298 } // End namespace Foam
299 
300 
301 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
302 
303 void Foam::argList::checkITstream(const ITstream& is, const label index)
304 {
305  const label remaining = is.nRemainingTokens();
306 
307  if (remaining)
308  {
309  std::cerr
310  << nl
311  << "--> FOAM WARNING:" << nl
312  << "Argument " << index << " has "
313  << remaining << " excess tokens" << nl << nl;
314  }
315  else if (!is.size())
316  {
317  std::cerr
318  << nl
319  << "--> FOAM WARNING:" << nl
320  << "Argument " << index << " had no tokens" << nl << nl;
321  }
322 }
323 
324 
325 void Foam::argList::checkITstream(const ITstream& is, const word& optName)
326 {
327  const label remaining = is.nRemainingTokens();
328 
329  if (remaining)
330  {
331  std::cerr
332  << nl
333  << "--> FOAM WARNING:" << nl
334  << "Option -" << optName << " has "
335  << remaining << " excess tokens" << nl << nl;
336  }
337  else if (!is.size())
338  {
339  std::cerr
340  << nl
341  << "--> FOAM WARNING:" << nl
342  << "Option -" << optName << " had no tokens" << nl << nl;
343  }
344 }
345 
346 
347 void Foam::argList::raiseBadInput(const word& optName) const
348 {
349  // Can use FatalError
350  // predicate checks are not used at the earliest stages
351  FatalErrorIn(executable())
352  << "Option -" << optName << " with invalid input" << nl
353  << exit(FatalError);
354 }
355 
356 
358 (
359  const string& argName,
360  const string& usage
361 )
362 {
363  validArgs.append(argName);
364 
365  // The first program argument starts at 1 - obtain index after the append
366 
367  const label index = validArgs.size();
368 
369  if (usage.empty())
370  {
371  argUsage.erase(index);
372  }
373  else
374  {
375  argUsage.set(index, usage);
376  }
377 }
378 
379 
381 (
382  const word& optName,
383  const string& usage,
384  bool advanced
385 )
386 {
387  argList::addOption(optName, "", usage, advanced);
388 }
389 
390 
392 (
393  const word& optName,
394  const string& param,
395  const string& usage,
396  bool advanced
397 )
398 {
399  validOptions.set(optName, param);
400  if (!usage.empty())
401  {
402  optionUsage.set(optName, usage);
403  }
404  if (advanced)
405  {
406  advancedOptions.set(optName);
407  }
408 }
409 
410 
411 void Foam::argList::setAdvanced(const word& optName, bool advanced)
412 {
413  if (advanced && validOptions.contains(optName))
414  {
415  advancedOptions.set(optName);
416  }
417  else
418  {
419  advancedOptions.erase(optName);
420  }
421 }
422 
423 
425 (
426  const word& optName,
427  std::pair<const char*,int> compat
428 )
429 {
430  validOptionsCompat.insert
431  (
432  compat.first,
433  std::pair<word,int>(optName, compat.second)
434  );
435 }
436 
437 
439 (
440  std::pair<const char*,int> compat,
441  bool expectArg
442 )
443 {
444  ignoreOptionsCompat.insert
445  (
446  compat.first,
447  std::pair<bool,int>(expectArg, compat.second)
448  );
449 }
450 
451 
453 (
454  const word& optName,
455  const string& usage
456 )
457 {
458  if (usage.empty())
459  {
460  optionUsage.erase(optName);
461  }
462  else
463  {
464  optionUsage.set(optName, usage);
465  }
466 }
467 
468 
469 void Foam::argList::addNote(const string& note)
470 {
471  if (!note.empty())
472  {
473  notes.append(note);
474  }
475 }
476 
477 
478 void Foam::argList::removeOption(const word& optName)
479 {
480  validOptions.erase(optName);
481  optionUsage.erase(optName);
482  advancedOptions.erase(optName);
483 }
484 
487 {
488  argsMandatory_ = false;
489 }
490 
493 {
494  return argsMandatory_;
495 }
496 
499 {
501 }
502 
503 
505 {
506  return (::Foam::infoDetailLevel > 0);
507 }
508 
509 
511 (
512  const string& usage,
513  bool advanced
514 )
515 {
516  const word optName("dry-run", false);
517 
518  argList::addBoolOption(optName, usage, advanced);
519  if (!advanced)
520  {
521  advancedOptions.erase(optName); // Avoid 'stickiness'
522  }
523 }
524 
525 
527 (
528  const string& usage,
529  bool advanced
530 )
531 {
532  const word optName("verbose", false);
533 
534  if (usage.empty())
535  {
537  (
538  optName,
539  "Additional verbosity (can be used multiple times)",
540  advanced
541  );
542  }
543  else
544  {
545  argList::addBoolOption(optName, usage, advanced);
546  }
547  if (!advanced)
548  {
549  advancedOptions.erase(optName); // Avoid 'stickiness'
550  }
551 }
552 
553 
554 void Foam::argList::noFunctionObjects(bool addWithOption)
555 {
556  removeOption("noFunctionObjects");
557 
558  // Ignore this bool option without warning
559  // - cannot tie to any particular version anyhow
560  ignoreOptionCompat({"noFunctionObjects", 0}, false);
561 
562  if (addWithOption)
563  {
565  (
566  "withFunctionObjects",
567  "Execute functionObjects"
568  // An advanced option, but seldom used so expose it more
569  );
570  }
571 }
572 
575 {
577 }
578 
579 
581 {
583  (
584  "no-libs",
585  "Disable use of the controlDict libs entry",
586  true // advanced option
587  );
588 }
589 
590 
592 {
593  removeOption("parallel");
594  removeOption("roots");
595  removeOption("decomposeParDict");
596  removeOption("hostRoots");
597  removeOption("world");
598  removeOption("mpi-threads");
599  validParOptions.clear();
600 }
601 
604 {
605  parallelThreads_ = true;
606 }
607 
610 {
611  checkProcessorDirectories_ = false;
612 }
613 
614 
615 bool Foam::argList::postProcess(int argc, char *argv[])
616 {
617  for (int argi = 1; argi < argc; ++argi)
618  {
619  const char *optName = argv[argi];
620 
621  if (optName[0] == '-')
622  {
623  ++optName; // Looks like an option, skip leading '-'
624 
625  if (optName == postProcessOptionName)
626  {
627  return true;
628  }
629  }
630  }
631 
632  return false;
633 }
634 
635 
636 int Foam::argList::verbose(int argc, char *argv[])
637 {
638  int num = 0;
639  for (int argi = 1; argi < argc; ++argi)
640  {
641  if (strcmp(argv[argi], "-verbose") == 0)
642  {
643  ++num;
644  }
645  }
646  return num;
647 }
648 
649 
650 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
653 {
654  return Foam::getEnv("FOAM_EXECUTABLE");
655 }
656 
657 
659 {
660  return Foam::getEnv("FOAM_CASE");
661 }
662 
663 
665 (
666  const fileName& input,
667  const bool caseTag
668 )
669 {
670  if (input.isAbsolute())
671  {
672  return input.relative(envGlobalPath(), caseTag);
673  }
674 
675  return input;
676 }
677 
678 
679 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
680 
681 Foam::word Foam::argList::optionCompat(const word& optName)
682 {
683  // NB: optName includes the leading '-' so that the return value
684  // can be used directly
685 
686  if (!validOptionsCompat.empty())
687  {
688  const auto fnd = validOptionsCompat.cfind(optName.substr(1));
689 
690  if (fnd.good())
691  {
692  const auto& alt = fnd.val();
693 
694  // No error::master() guard - only called on master anyhow
695  if (error::warnAboutAge(alt.second))
696  {
697  std::cerr
698  << "--> FOAM IOWarning :" << nl
699  << " Found [v" << alt.second << "] '"
700  << optName << "' instead of '-"
701  << alt.first << "' option"
702  << nl
703  << std::endl;
704 
705  error::warnAboutAge("option", alt.second);
706  }
707 
708  return "-" + alt.first;
709  }
710  }
711 
712  // Nothing found - pass through the original input
713  return optName;
714 }
715 
716 
717 int Foam::argList::optionIgnore(const word& optName)
718 {
719  // NB: optName is without the leading '-'
720 
721  if (!ignoreOptionsCompat.empty())
722  {
723  const auto fnd = ignoreOptionsCompat.cfind(optName);
724 
725  if (fnd.good())
726  {
727  const auto& alt = fnd.val();
728 
729  // Number to skip (including the option itself)
730  // '-option ARG' or '-option'
731  const int nskip = (alt.first ? 2 : 1);
732 
733  // No error::master() guard - only called on master anyhow
734  if (error::warnAboutAge(alt.second))
735  {
736  std::cerr
737  << "--> FOAM IOWarning :" << nl
738  << " Ignoring [v" << alt.second << "] '-"
739  << optName << (nskip > 1 ? " ARG" : "")
740  << "' option"
741  << nl
742  << std::endl;
743 
744  error::warnAboutAge("option", alt.second);
745  }
746 
747  return nskip;
748  }
749  }
750 
751  // TBD: could ignore -verbose, -dry-run etc if they are not active...
752 
753  return 0; // Do not skip
754 }
755 
756 
757 bool Foam::argList::regroupArgv(int& argc, char**& argv)
758 {
759  int nArgs = 1;
760  int ignore = 0;
761  unsigned depth = 0;
762  string group; // For grouping ( ... ) arguments
763 
764  // Note: we rewrite directly into args_
765  // and use a second pass to sort out args/options
766 
767  args_[0] = fileName(argv[0]);
768  for (int argi = 1; argi < argc; ++argi)
769  {
770  const char *optName = argv[argi];
771 
772  if (optName[0] == '(' && optName[1] == '\0')
773  {
774  // Begin list
775  ++depth;
776  group += '(';
777  }
778  else if (optName[0] == ')' && optName[1] == '\0')
779  {
780  if (depth)
781  {
782  // End list
783  --depth;
784  group += ')';
785  if (!depth)
786  {
787  args_[nArgs++] = group;
788  group.clear();
789  }
790  }
791  else
792  {
793  // A stray ')' - likely never happens
794  args_[nArgs++] = argv[argi];
795  }
796  }
797  else if (depth)
798  {
799  // Quote each string element
800  group += '"';
801  group += argv[argi];
802  group += '"';
803  }
804  else if (optName[0] == '-')
805  {
806  ++optName; // Looks like an option, skip leading '-'
807 
808  if (validOptions.contains(optName))
809  {
810  // Known option name
811  args_[nArgs++] = argv[argi];
812  }
813  else if ((ignore = optionIgnore(optName)) > 0)
814  {
815  // Option to be ignored (with/without an argument)
816  if (ignore > 1)
817  {
818  ++argi;
819  }
820  }
821  else
822  {
823  // Try alias for the option name
824  args_[nArgs++] = optionCompat(argv[argi]);
825  }
826  }
827  else
828  {
829  args_[nArgs++] = argv[argi];
830  }
831  }
832 
833  if (group.size())
834  {
835  // Group(s) not closed, but flush anything still pending
836  args_[nArgs++] = group;
837  }
838 
839  args_.resize(nArgs);
840 
841  std::string::size_type len = (nArgs-1); // Spaces between args
842  for (const auto& s : args_)
843  {
844  len += s.length();
845  }
846 
847  // Length needed for regrouped command-line
848  commandLine_.reserve(len);
849 
850  return nArgs < argc;
851 }
852 
853 
854 void Foam::argList::setCasePaths()
855 {
856  fileName caseDir;
857 
858  const auto optIter = options_.cfind("case"); // [-case dir] specified?
859 
860  if (optIter.good())
861  {
862  caseDir = fileName::validate(optIter.val()); // includes 'clean'
863 
864  if (caseDir.empty() || caseDir == ".")
865  {
866  // Treat "", "." and "./" as if -case was not specified
867  caseDir = cwd();
868  options_.erase("case");
869  }
870  else
871  {
872  caseDir.expand();
873  caseDir.toAbsolute();
874  }
875  }
876  else
877  {
878  // Nothing specified, use the current dir
879  caseDir = cwd();
880  }
881 
882  // The caseDir is a cleaned, absolute path
883 
884  rootPath_ = caseDir.path();
885  globalCase_ = caseDir.name();
886  case_ = globalCase_; // The (processor) local case name
887 
888  // OPENFOAM API
889  setEnv("FOAM_API", std::to_string(foamVersion::api), true);
890 
891  // Global case (directory) and case-name as environment variables
892  setEnv("FOAM_CASE", caseDir, true);
893  setEnv("FOAM_CASENAME", globalCase_, true);
894 
895  // Executable name, unless already present in the environment
896  setEnv("FOAM_EXECUTABLE", executable_, false);
897 }
898 
899 
900 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
901 
903 (
904  int& argc,
905  char**& argv,
906  bool checkArgs,
907  bool checkOpts,
908  bool initialise
909 )
910 :
911  runControl_(),
912  args_(argc),
913  options_(argc),
914  libs_()
915 {
916  // Pre-scan for some options needed for initial setup:
917  // -fileHandler (takes an argument)
918  // -mpi-threads (bool option)
919  //
920  // Also handle -dry-run and -verbose counting
921  // (it is left to the application to decide what to do with them).
922  // Detect any parallel run options
923 
924  word fileHandlerName;
925 
926  if (parallelThreads_)
927  {
928  // Default -mpi-threads configured statically from application
929  runControl_.threads(true);
930  }
931 
932  for (int argi = 1; argi < argc; ++argi)
933  {
934  const char *optName = argv[argi];
935 
936  if (optName[0] == '-')
937  {
938  ++optName; // Looks like an option, skip leading '-'
939  bool emitErrorMessage = false;
940 
941  if (strcmp(optName, "dry-run") == 0)
942  {
943  runControl_.incrDryRun();
944  }
945  else if (strcmp(optName, "verbose") == 0)
946  {
947  runControl_.incrVerbose();
948  }
949  else if (strcmp(optName, "mpi-threads") == 0)
950  {
951  runControl_.threads(true);
952  }
953  else if (strcmp(optName, "fileHandler") == 0)
954  {
955  // Requires a parameter
956  if (argi < argc-1)
957  {
958  ++argi;
959  fileHandlerName = argv[argi];
960  }
961  else
962  {
963  emitErrorMessage = true;
964  }
965  }
966  else if (validParOptions.contains(optName))
967  {
968  // Contains a parallel run option
969  runControl_.parRun(true);
970  }
971 
972  if (emitErrorMessage)
973  {
974  // Missing argument: emit message but not exit or
975  // FatalError since Pstream etc are not yet initialised
976 
977  Info<< nl
978  << "Error: option '-" << optName
979  << "' requires an argument" << nl << nl;
980 
981  //NO: UPstream::exit(1); // works for serial and parallel
982  }
983  }
984  }
985 
986  // No -fileHandler specifed, get from environment or use default
987  if (fileHandlerName.empty())
988  {
989  fileHandlerName = Foam::getEnv("FOAM_FILEHANDLER");
990  if (fileHandlerName.empty())
991  {
992  fileHandlerName = fileOperation::defaultFileHandler;
993  }
994  }
995 
996  // Parse out any additional fileHandler-specific options
997  // (may alter argv list). Recover its threading requirements
998  {
999  auto fileOperationInit = fileOperations::fileOperationInitialise::New
1000  (
1001  fileHandlerName,
1002  argc,
1003  argv
1004  );
1005 
1006  if (fileOperationInit && fileOperationInit->needsThreading())
1007  {
1008  runControl_.threads(true);
1009  }
1010  }
1011 
1012  // Parallel job options detected?
1013  // - start parallel run (possibly filters argv as a side-effect)
1014  if (runControl_.parRun())
1015  {
1016  runControl_.runPar(argc, argv);
1017  }
1018 
1019 
1020  // ------------------------------------------------------------------------
1021 
1022  // Convert argv -> args_ and capture ( ... ) lists
1023  regroupArgv(argc, argv);
1024  commandLine_ += args_[0];
1025 
1026  // Set executable name immediately - useful when emitting errors.
1027  executable_ = fileName(args_[0]).name();
1028 
1029  // Check arguments and options, argv[0] was already handled
1030  int nArgs = 1;
1031  for (int argi = 1; argi < args_.size(); ++argi)
1032  {
1033  commandLine_ += ' ';
1034  commandLine_ += args_[argi];
1035 
1036  const char *optName = args_[argi].data();
1037 
1038  if (optName[0] == '-')
1039  {
1040  ++optName; // Looks like an option, skip leading '-'
1041 
1042  if (!*optName)
1043  {
1044  Warning
1045  << "Ignoring lone '-' on the command-line" << endl;
1046  continue;
1047  }
1048 
1049  // Option known and expects an argument?
1050  // - use Switch for a tri-state
1051  // True : known option, expects a parameter
1052  // False : known option, no parameter
1053  // bad() : unknown option
1054 
1055  Switch wantArg(Switch::INVALID);
1056  auto optIter = validOptions.cfind(optName);
1057  if
1058  (
1059  optIter.good()
1060  || (optIter = validParOptions.cfind(optName)).good()
1061  )
1062  {
1063  wantArg = !optIter.val().empty();
1064  }
1065 
1066 
1067  if (wantArg)
1068  {
1069  // Option expects a parameter
1070  // - get it or emit a FatalError.
1071 
1072  ++argi;
1073  if (argi >= args_.size())
1074  {
1076 
1077  Info<< nl
1078  <<"Error: option '-" << optName
1079  << "' requires an argument" << nl << nl
1080  << "See '" << executable_ << " -help' for usage" << nl
1081  << " or '" << executable_
1082  << " -help-full' for extended usage" << nl
1083  << nl;
1084 
1085  UPstream::exit(1); // works for serial and parallel
1086  }
1087 
1088  commandLine_ += ' ';
1089  commandLine_ += args_[argi];
1090 
1091  //
1092  // Special handling of these options
1093  //
1094 
1095  if (strcmp(optName, "lib") == 0)
1096  {
1097  // The '-lib' option:
1098  // Append name(s) to libs for later opening
1099  libs().append(this->getList<fileName>(argi));
1100  }
1101  else if (strcmp(optName, "debug-switch") == 0)
1102  {
1103  // The '-debug-switch' option:
1104  // change registered debug switch
1105  DetailInfo << "debug-switch ";
1107  .setNamedValue(args_[argi], 1, true);
1108  }
1109  else if (strcmp(optName, "info-switch") == 0)
1110  {
1111  // The '-info-switch' option:
1112  // change registered info switch
1113  DetailInfo << "info-switch ";
1115  .setNamedValue(args_[argi], 1, true);
1116  }
1117  else if (strcmp(optName, "opt-switch") == 0)
1118  {
1119  // The '-opt-switch' option:
1120  // change registered optimisation switch
1121  DetailInfo << "opt-switch ";
1123  .setNamedValue(args_[argi], 1, true);
1124  }
1125  else
1126  {
1127  // Regular option (with a parameter):
1128  // Duplicates handled by using the last -option specified
1129  options_.set(optName, args_[argi]);
1130  }
1131  }
1132  else
1133  {
1134  // All other options (including unknown ones) are simply
1135  // registered as existing.
1136 
1137  options_.insert(optName, "");
1138 
1139  // // Special increment handling for some known flags
1140  // if (wantArg.good())
1141  // {
1142  // ...
1143  // }
1144  }
1145  }
1146  else
1147  {
1148  if (nArgs != argi)
1149  {
1150  args_[nArgs] = args_[argi];
1151  }
1152  ++nArgs;
1153  }
1154  }
1155 
1156  args_.resize(nArgs);
1157 
1158  parse(checkArgs, checkOpts, initialise);
1159 }
1160 
1161 
1163 (
1164  const argList& args,
1165  const HashTable<string>& options,
1166  bool checkArgs,
1167  bool checkOpts,
1168  bool initialise
1169 )
1170 :
1171  runControl_(args.runControl_),
1172  args_(args.args_),
1173  options_(options),
1174  libs_(),
1175  executable_(args.executable_),
1176  rootPath_(args.rootPath_),
1177  globalCase_(args.globalCase_),
1178  case_(args.case_),
1179  commandLine_(args.commandLine_)
1180 {
1181  parse(checkArgs, checkOpts, initialise);
1182 }
1183 
1184 
1186 (
1187  bool checkArgs,
1188  bool checkOpts,
1189  bool initialise
1190 )
1191 {
1192  // Help/documentation options:
1193  // -doc Display documentation in browser
1194  // -doc-source Display source code in browser
1195  // -help Display short help and exit
1196  // -help-compat Display compatibility options
1197  // -help-full Display full help and exit
1198  {
1199  bool quickExit = false;
1200 
1201  // Display either application or source documentation, not both
1202  if (options_.contains("doc"))
1203  {
1204  displayDoc(false);
1205  quickExit = true;
1206  }
1207  else if (options_.contains("doc-source"))
1208  {
1209  displayDoc(true);
1210  quickExit = true;
1211  }
1212 
1213  // Display either short or full help, not both
1214  if (options_.contains("help-full"))
1215  {
1216  printUsage(true);
1217  quickExit = true;
1218  }
1219  else if (options_.contains("help-notes"))
1220  {
1221  printNotes();
1222  Info<< nl;
1223  quickExit = true;
1224  }
1225  else if (options_.contains("help"))
1226  {
1227  printUsage(false);
1228  quickExit = true;
1229  }
1230  else if (options_.contains("help-man"))
1231  {
1232  printMan();
1233  quickExit = true;
1234  }
1235 
1236  // Allow independent display of compatibility information
1237  if (options_.contains("help-compat"))
1238  {
1239  printCompat();
1240  quickExit = true;
1241  }
1242 
1243  if (quickExit)
1244  {
1245  std::exit(0);
1246  }
1247  }
1248 
1249  // Print the collected error messages and exit if check fails
1250  if (!check(checkArgs, checkOpts))
1251  {
1253  FatalError.write(Info, false);
1254 
1255  UPstream::exit(1); // works for serial and parallel
1256  }
1257 
1258  if (initialise)
1259  {
1260  const string dateString = clock::date();
1261  const string timeString = clock::clockTime();
1262 
1263  // Print the banner once only for parallel runs
1264  if (Pstream::master() && bannerEnabled())
1265  {
1267  << "Build : ";
1268 
1269  if (foamVersion::build.size())
1270  {
1271  Info<< foamVersion::build.c_str() << ' ';
1272  }
1273 
1274  Info<< "OPENFOAM=" << foamVersion::api;
1275 
1276  if (foamVersion::patched())
1277  {
1278  // Patch-level, when defined
1279  Info<< " patch=" << foamVersion::patch.c_str();
1280  }
1281 
1282  Info<< " version=" << foamVersion::version.c_str();
1283 
1284  Info<< nl
1285  << "Arch : " << foamVersion::buildArch << nl
1286  << "Exec : " << commandLine_.c_str() << nl
1287  << "Date : " << dateString.c_str() << nl
1288  << "Time : " << timeString.c_str() << nl
1289  << "Host : " << Foam::hostName().c_str() << nl
1290  << "PID : " << pid() << nl;
1291  }
1292 
1293  jobInfo.add("startDate", dateString);
1294  jobInfo.add("startTime", timeString);
1295  jobInfo.add("userName", userName());
1296 
1297  jobInfo.add("foamApi", foamVersion::api);
1298  jobInfo.add("foamVersion", word(foamVersion::version));
1299 
1300  // Add build information - only use the first word
1301  {
1302  std::string build(foamVersion::build);
1303  const auto space = build.find(' ');
1304  if (space != std::string::npos)
1305  {
1306  build.resize(space);
1307  }
1308  jobInfo.add("foamBuild", build);
1309  }
1310 
1311  jobInfo.add("code", executable_);
1312  jobInfo.add("argList", commandLine_);
1313  jobInfo.add("currentDir", cwd());
1314  jobInfo.add("PPID", ppid());
1315  jobInfo.add("PGID", pgid());
1316 
1317  // Load additional libraries (verbosity according to banner setting)
1318  libs().open(bannerEnabled());
1319  }
1320 
1321 
1322  // Set fileHandler. In increasing order of priority:
1323  // 1. default = uncollated
1324  // 2. env variable "FOAM_FILEHANDLER"
1325  // 3. etc/controlDict optimisationSwitches 'fileHandler'
1326  // 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)
1327  // 5. '-fileHandler' commmand-line option
1328 
1329  {
1330  word fileHandlerName
1331  (
1332  options_.lookup("fileHandler", Foam::getEnv("FOAM_FILEHANDLER"))
1333  );
1334 
1335  if (fileHandlerName.empty())
1336  {
1337  fileHandlerName = fileOperation::defaultFileHandler;
1338  }
1339 
1341  (
1342  fileOperation::New(fileHandlerName, bannerEnabled())
1343  );
1344  }
1345 
1346 
1347  stringList hostMachine;
1348  stringList hostProcs;
1349  const int writeHostsSwitch = Foam::debug::infoSwitch("writeHosts", 1);
1350  const int writeRootsSwitch = Foam::debug::infoSwitch("writeRoots", 1);
1351 
1352  // Collect machine/pid, and check that the build is identical
1353  if (runControl_.parRun())
1354  {
1355  if (Pstream::master())
1356  {
1357  hostMachine.resize(Pstream::nProcs()-1);
1358  hostProcs.resize(Pstream::nProcs()-1);
1359  string procBuild;
1360  label procPid;
1361  int proci = 0;
1362  for (const int subproci : Pstream::subProcs())
1363  {
1364  IPstream fromSubproc(Pstream::commsTypes::scheduled, subproci);
1365 
1366  fromSubproc >> procBuild >> hostMachine[proci] >> procPid;
1367 
1368  hostProcs[proci] = hostMachine[proci] + "." + name(procPid);
1369  ++proci;
1370 
1371  // Verify that all processors are running the same build
1372  if (procBuild != foamVersion::build)
1373  {
1374  FatalErrorIn(executable())
1375  << "Running build version " << foamVersion::build
1376  << " but proc " << subproci << " is running "
1377  << procBuild << nl
1378  << exit(FatalError);
1379  }
1380  }
1381  }
1382  else
1383  {
1384  OPstream toMaster
1385  (
1388  );
1389  toMaster << foamVersion::build << Foam::hostName() << Foam::pid();
1390  }
1391  }
1392 
1393 
1394  // Case is a single processor run unless it is running parallel
1395  int nProcs = 1;
1396 
1397  // Roots if running distributed
1398  fileNameList roots;
1399 
1400  // If this actually is a parallel run
1401  if (runControl_.parRun())
1402  {
1403  // For the master
1404  if (Pstream::master())
1405  {
1406  // Establish rootPath_/globalCase_/case_ for master
1407  setCasePaths();
1408 
1409  // The system/decomposeParDict (or equivalent)
1410  fileName source;
1411 
1412  if (this->readIfPresent("decomposeParDict", source))
1413  {
1414  bool adjustOpt = false;
1415 
1416  if (isDir(source))
1417  {
1418  source /= "decomposeParDict";
1419  adjustOpt = true;
1420  }
1421 
1422  // Case-relative if not absolute and not "./" etc
1423  if (!source.isAbsolute() && !source.starts_with('.'))
1424  {
1425  source = rootPath_/globalCase_/source;
1426  adjustOpt = true;
1427  }
1428 
1429  // Could also check for absolute path, but shouldn't be needed
1430  if (adjustOpt)
1431  {
1432  source.clean(); // Remove unneeded ".."
1433  options_.set("decomposeParDict", source);
1434  }
1435  }
1436 
1437  // If running distributed (different roots for different procs)
1438  label dictNProcs = -1;
1439  if (this->readListIfPresent("roots", roots))
1440  {
1441  source = "-roots";
1442  runControl_.distributed(true);
1443 
1444  if (roots.empty())
1445  {
1447  << "The -roots option must contain values"
1448  << exit(FatalError);
1449  }
1450  if (roots.size() > 1)
1451  {
1452  dictNProcs = roots.size()+1;
1453  }
1454  }
1455  else if (options_.contains("hostRoots"))
1456  {
1457  source = "-hostRoots";
1458  runControl_.distributed(true);
1459 
1460  ITstream is(this->lookup("hostRoots"));
1461 
1462  List<Tuple2<wordRe, fileName>> hostRoots(is);
1463  checkITstream(is, "hostRoots");
1464 
1465  if (hostRoots.empty())
1466  {
1468  << "The -hostRoots option must contain values"
1469  << exit(FatalError);
1470  }
1471 
1472  // Match machine names to roots
1473  roots.resize(Pstream::nProcs()-1, fileName::null);
1474  for (const auto& hostRoot : hostRoots)
1475  {
1476  labelList matched
1477  (
1478  findMatchingStrings(hostRoot.first(), hostMachine)
1479  );
1480  for (const label matchi : matched)
1481  {
1482  if (!roots[matchi].empty())
1483  {
1485  << "Multiple matching roots for "
1486  << hostMachine[matchi] << " in "
1487  << hostRoots << nl
1488  << exit(FatalError);
1489  }
1490 
1491  roots[matchi] = hostRoot.second();
1492  }
1493  }
1494 
1495  // Check
1496  forAll(roots, hosti)
1497  {
1498  if (roots[hosti].empty())
1499  {
1501  << "No matching roots for "
1502  << hostMachine[hosti] << " in "
1503  << hostRoots << nl
1504  << exit(FatalError);
1505  }
1506  }
1507 
1508  if (roots.size() > 1)
1509  {
1510  dictNProcs = roots.size()+1;
1511  }
1512  }
1513  else if (checkProcessorDirectories_ && Pstream::nProcs() > 1)
1514  {
1515  // Check values from decomposeParDict
1516 
1517  const bool useDefault = source.empty();
1518  if (useDefault)
1519  {
1520  source = rootPath_/globalCase_/"system"/"decomposeParDict";
1521  }
1522 
1523  // Disable any parallel comms happening inside the fileHandler
1524  // since we are on master. This can happen e.g. inside
1525  // the masterUncollated/collated handler. Note that we
1526  // also have to protect the actual dictionary parsing since
1527  // it might trigger file access (e.g. #include, #codeStream)
1528  const bool oldParRun = Pstream::parRun(false);
1529 
1530  autoPtr<ISstream> dictStream
1531  (
1532  fileHandler().NewIFstream(source)
1533  );
1534 
1535  if (dictStream && dictStream->good())
1536  {
1537  // Get numberOfSubdomains if it exists.
1538  // - mandatory when running with distributed roots
1539 
1540  IOobjectOption::readOption nDomainsReadOpt
1542 
1543  dictionary decompDict(*dictStream);
1544 
1545  if (decompDict.getOrDefault("distributed", false))
1546  {
1547  nDomainsReadOpt = IOobjectOption::MUST_READ;
1548  runControl_.distributed(true);
1549  decompDict.readEntry("roots", roots);
1550 
1551  if (roots.empty())
1552  {
1553  DetailInfo
1554  << "WARNING: running distributed"
1555  << " but did not specify roots!" << nl;
1556  }
1557  }
1558 
1559  decompDict.readEntry
1560  (
1561  "numberOfSubdomains",
1562  dictNProcs,
1564  nDomainsReadOpt
1565  );
1566  }
1567  else
1568  {
1569  if (useDefault)
1570  {
1571  // Optional if using default location
1572  DetailInfo
1573  << "WARNING: running without decomposeParDict "
1574  << this->relativePath(source) << nl;
1575  }
1576  else
1577  {
1578  // Mandatory if specified as -decomposeParDict
1579  FatalError
1580  << "Cannot read decomposeParDict: "
1581  << this->relativePath(source) << nl
1582  << exit(FatalError);
1583  }
1584  }
1585 
1586  Pstream::parRun(oldParRun); // Restore parallel state
1587 
1588  if (Pstream::nProcs() == 1)
1589  {
1590  Warning
1591  << "Running parallel on single processor. This only"
1592  << " makes sense for multi-world simulation" << endl;
1593  dictNProcs = 1;
1594  }
1595  }
1596 
1597  // Convenience:
1598  // when a single root is specified, use it for all processes
1599  if (roots.size() == 1)
1600  {
1601  const fileName rootName(roots[0]);
1602  roots.resize(Pstream::nProcs()-1, rootName);
1603 
1604  // Adjust dictNProcs for command-line '-roots' option
1605  if (dictNProcs <= 0)
1606  {
1607  dictNProcs = roots.size()+1;
1608  }
1609  }
1610 
1611 
1612  // Check number of processors.
1613  // nProcs => number of actual procs
1614  // dictNProcs => number of procs specified in decompositionDict
1615  // nProcDirs => number of processor directories
1616  // (n/a when running distributed)
1617  //
1618  // - normal running : nProcs = dictNProcs = nProcDirs
1619  // - decomposition to more processors : nProcs = dictNProcs
1620  // - decomposition to fewer processors : nProcs = nProcDirs
1621  if
1622  (
1623  checkProcessorDirectories_
1624  && Pstream::nProcs() > 1
1625  && dictNProcs > Pstream::nProcs()
1626  )
1627  {
1628  FatalError
1629  << this->relativePath(source)
1630  << " specifies " << dictNProcs
1631  << " processors but job was started with "
1632  << Pstream::nProcs() << " processors."
1633  << exit(FatalError);
1634  }
1635 
1636  // Distributed data
1637  if (roots.size())
1638  {
1639  if (roots.size() != Pstream::nProcs()-1)
1640  {
1641  FatalError
1642  << "number of entries in roots "
1643  << roots.size()
1644  << " is not equal to the number of sub-processes "
1645  << Pstream::nProcs()-1
1646  << exit(FatalError);
1647  }
1648 
1649  for (fileName& dir : roots)
1650  {
1651  dir.expand();
1652  }
1653 
1654  // Distribute the master's argument list (with new root)
1655  const bool hadCaseOpt = options_.contains("case");
1656  for (const int subproci : Pstream::subProcs())
1657  {
1658  options_.set("case", roots[subproci-1]/globalCase_);
1659 
1660  OPstream toProc(Pstream::commsTypes::scheduled, subproci);
1661 
1662  toProc
1663  << args_ << options_
1664  << runControl_.distributed()
1665  << label(runControl_.dryRun())
1666  << label(runControl_.verbose());
1667  }
1668  options_.erase("case");
1669 
1670  // Restore [-case dir]
1671  if (hadCaseOpt)
1672  {
1673  options_.set("case", rootPath_/globalCase_);
1674  }
1675  }
1676  else
1677  {
1678  // Possibly going to fewer processors.
1679  // Check if all procDirs are there.
1680  if
1681  (
1682  checkProcessorDirectories_
1683  && Pstream::nProcs() > 1
1684  && dictNProcs >= 1
1685  && dictNProcs < Pstream::nProcs()
1686  )
1687  {
1688  label nProcDirs = 0;
1689  while
1690  (
1691  isDir
1692  (
1693  rootPath_/globalCase_
1694  / ("processor" + Foam::name(++nProcDirs))
1695  )
1696  )
1697  {}
1698 
1699  if (nProcDirs != Pstream::nProcs())
1700  {
1701  FatalError
1702  << "number of processor directories = "
1703  << nProcDirs
1704  << " is not equal to the number of processors = "
1705  << Pstream::nProcs()
1706  << exit(FatalError);
1707  }
1708  }
1709 
1710  // Distribute the master's argument list (unaltered)
1711  for (const int subproci : Pstream::subProcs())
1712  {
1713  OPstream toProc(Pstream::commsTypes::scheduled, subproci);
1714 
1715  toProc
1716  << args_ << options_
1717  << runControl_.distributed()
1718  << label(runControl_.dryRun())
1719  << label(runControl_.verbose());
1720  }
1721  }
1722  }
1723  else
1724  {
1725  // Collect the master's argument list
1726  bool isDistributed;
1727  label numDryRun, numVerbose;
1728 
1729  IPstream fromMaster
1730  (
1733  );
1734 
1735  fromMaster
1736  >> args_ >> options_
1737  >> isDistributed
1738  >> numDryRun >> numVerbose;
1739 
1740  runControl_.distributed(isDistributed);
1741  runControl_.dryRun(numDryRun);
1742  runControl_.verbose(numVerbose);
1743 
1744  // Establish rootPath_/globalCase_/case_ for sub-process
1745  setCasePaths();
1746  }
1747 
1748  nProcs = Pstream::nProcs();
1749  if (Pstream::nProcs() > 1)
1750  {
1751  case_ = globalCase_/("processor" + Foam::name(Pstream::myProcNo()));
1752  }
1753  else
1754  {
1755  case_ = globalCase_;
1756  }
1757  }
1758  else
1759  {
1760  // Establish rootPath_/globalCase_/case_
1761  setCasePaths();
1762  case_ = globalCase_; // Redundant, but extra safety?
1763  }
1764 
1765  // If needed, adjust fileHandler for distributed roots
1766  if (runControl_.distributed())
1767  {
1769  {
1770  fileOperation::fileHandlerPtr_->distributed(true);
1771  }
1772  }
1773 
1774  // Keep/discard sub-process host/root information for reporting:
1775  if (Pstream::master() && runControl_.parRun())
1776  {
1777  if (!writeHostsSwitch)
1778  {
1779  // Clear here to ensures it doesn't show in the jobInfo
1780  hostProcs.clear();
1781  }
1782  if (!writeRootsSwitch)
1783  {
1784  roots.clear();
1785  }
1786  }
1787 
1788  if (Pstream::master() && bannerEnabled())
1789  {
1790  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
1791  << "nProcs : " << nProcs << nl;
1792 
1793  if (runControl_.parRun())
1794  {
1795  if (hostProcs.size())
1796  {
1797  if (writeHostsSwitch == 1)
1798  {
1799  // Compact output (see etc/controlDict)
1800  printHostsSubscription(hostProcs);
1801  }
1802  else if (writeHostsSwitch)
1803  {
1804  // Full output of "host.pid"
1805  Info<< "Hosts :\n(" << nl;
1806 
1807  // Include master in the list
1808  Info<< " " << Foam::hostName().c_str() << '.'
1809  << Foam::pid() << nl;
1810 
1811  // Sub-processes
1812  for (const auto& str : hostProcs)
1813  {
1814  Info<< " " << str.c_str() << nl;
1815  }
1816  Info<< ')' << nl;
1817  }
1818  }
1819  if (roots.size())
1820  {
1821  bool hasPrinted = false;
1822  if (writeRootsSwitch == 1)
1823  {
1824  // Compact output
1825  hasPrinted = printRootsSubscription(hostProcs, roots);
1826  }
1827  if (writeRootsSwitch && !hasPrinted)
1828  {
1829  // Full output
1830  Info<< "Roots : " << roots << nl;
1831  }
1832  }
1833  Info<< "Pstream initialized with:" << nl
1834  << " floatTransfer : "
1836  << " nProcsSimpleSum : "
1838  << " nonBlockingExchange: "
1840  << " (tuning: " << UPstream::tuning_NBX_ << ')' << nl
1841  << " exchange algorithm : "
1843  << " commsType : "
1845  << " polling iterations : "
1847 
1848  if (UPstream::allWorlds().size() > 1)
1849  {
1850  Info<< " worlds : "
1852  << " world : " << UPstream::myWorld()
1853  << nl;
1854  }
1855  }
1856  }
1857 
1858  if (initialise)
1859  {
1860  jobInfo.add("root", rootPath_);
1861  jobInfo.add("case", globalCase_);
1862  jobInfo.add("nProcs", nProcs);
1863  if (hostProcs.size())
1864  {
1865  jobInfo.add("hosts", hostProcs);
1866  }
1867  if (roots.size())
1868  {
1869  jobInfo.add("roots", roots);
1870  }
1871  jobInfo.write();
1872 
1873  // Switch on signal trapping. We have to wait until after Pstream::init
1874  // since this sets up its own ones.
1875  sigFpe::set(bannerEnabled());
1876  sigInt::set(bannerEnabled());
1877  sigQuit::set(bannerEnabled());
1878  sigSegv::set(bannerEnabled());
1879 
1880  if (Pstream::master() && bannerEnabled())
1881  {
1882  Info<< "fileModificationChecking : "
1883  << "Monitoring run-time modified files using "
1885  [
1887  ];
1888  if
1889  (
1892  )
1893  {
1895  {
1896  Info<< " (fileModificationSkew "
1898  << ")";
1899  }
1901  {
1902  Info<< " (fileModificationSkew "
1904  << ", maxFileModificationPolls "
1906  << ")";
1907  }
1908  else
1909  {
1911  << "Invalid setting for maxFileModificationPolls "
1913  << exit(FatalError);
1914  }
1915  }
1916  Info<< nl;
1917 
1918  Info<< "allowSystemOperations : ";
1920  {
1921  Info<< "Allowing";
1922  }
1923  else
1924  {
1925  Info<< "Disallowing";
1926  }
1927  Info<< " user-supplied system call operations" << nl
1928  << nl;
1930  }
1931  }
1932 }
1933 
1934 
1935 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1936 
1938 {
1939  jobInfo.stop(); // Normal job termination
1940 
1941  // Delete file handler to flush any remaining IO
1942  (void) fileOperation::fileHandler(nullptr);
1943 }
1944 
1945 
1946 // * * * * * * * * * * * * * * * Capabilities * * * * * * * * * * * * * * * //
1947 
1949 {
1950  if (validOptions.contains("withFunctionObjects"))
1951  {
1952  // '-withFunctionObjects' is available and explicitly enabled
1953  return options_.contains("withFunctionObjects");
1954  }
1955  else if (validOptions.contains("noFunctionObjects"))
1956  {
1957  // '-noFunctionObjects' is available and not explicitly disabled
1958  return !options_.contains("noFunctionObjects");
1959  }
1960 
1961  // Disallow functions if there is no way to enable/disable them
1962  return false;
1963 }
1964 
1965 
1966 bool Foam::argList::allowLibs() const
1968  return !options_.contains("no-libs");
1969 }
1970 
1971 
1972 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1973 
1974 Foam::label Foam::argList::count(const UList<word>& optionNames) const
1975 {
1976  label num = 0;
1977  for (const word& optName : optionNames)
1978  {
1979  if (options_.contains(optName))
1980  {
1981  ++num;
1982  }
1983  }
1984  return num;
1985 }
1986 
1987 
1988 Foam::label Foam::argList::count(std::initializer_list<word> optionNames) const
1989 {
1990  label num = 0;
1991  for (const word& optName : optionNames)
1992  {
1993  if (options_.contains(optName))
1994  {
1995  ++num;
1996  }
1997  }
1998  return num;
1999 }
2000 
2001 
2002 bool Foam::argList::setOption(const word& optName, const string& param)
2003 {
2004  // Some options are always protected
2005  if
2006  (
2007  optName == "case"
2008  || optName == "parallel"
2009  || optName == "roots"
2010  )
2011  {
2013  <<"Option: '" << optName << "' is protected" << nl
2014  << exit(FatalError);
2015  return false;
2016  }
2017 
2018  const auto optIter = options_.cfind(optName);
2019 
2020  if (!optIter.good() || (optIter.val() != param))
2021  {
2022  options_.set(optName, param);
2023  return true;
2024  }
2025 
2026  return false;
2027 }
2028 
2029 
2030 bool Foam::argList::unsetOption(const word& optName)
2031 {
2032  // Some options are always protected
2033  if
2034  (
2035  optName == "case"
2036  || optName == "parallel"
2037  || optName == "roots"
2038  )
2039  {
2041  <<"Option: '" << optName << "' is protected" << nl
2042  << exit(FatalError);
2043  return false;
2044  }
2045 
2046  // Remove the option, return true if state changed
2047  return options_.erase(optName);
2048 }
2049 
2050 
2051 void Foam::argList::displayDoc(bool source) const
2052 {
2053  const dictionary& docDict = debug::controlDict().subDict("Documentation");
2054  fileNameList docDirs(docDict.get<fileNameList>("doxyDocDirs"));
2055  fileName docExt(docDict.get<fileName>("doxySourceFileExt"));
2056 
2057  // For source code: change xxx_8C.html to xxx_8C_source.html
2058  if (source)
2059  {
2060  docExt.replace(".", "_source.");
2061  }
2062 
2063  fileName url;
2064 
2065  for (const fileName& dir : docDirs)
2066  {
2067  // The http protocols are last in the list
2068  if (dir.starts_with("http:") || dir.starts_with("https:"))
2069  {
2070  url = dir/executable_ + docExt;
2071  break;
2072  }
2073 
2074  fileName docFile = stringOps::expand(dir/executable_ + docExt);
2075 
2076  if
2077  (
2078  docFile.starts_with("file://")
2079  ? isFile(docFile.substr(7)) // check part after "file://"
2080  : isFile(docFile)
2081  )
2082  {
2083  url = std::move(docFile);
2084  break;
2085  }
2086  }
2087 
2088  if (url.empty())
2089  {
2090  Info<< nl
2091  << "No documentation found for " << executable_
2092  << ", but you can use -help to display the usage\n" << endl;
2093 
2094  return;
2095  }
2096 
2097  string docBrowser = getEnv("FOAM_DOC_BROWSER");
2098  if (docBrowser.empty())
2099  {
2100  docDict.readEntry("docBrowser", docBrowser);
2101  }
2102 
2103  // Can use FOAM_DOC_BROWSER='application file://%f' if required
2104  if (docBrowser.contains("%f"))
2105  {
2106  docBrowser.replace("%f", url);
2107  }
2108  else
2109  {
2110  docBrowser += " " + url;
2111  }
2112 
2113  // Split on whitespace to use safer version of Foam::system()
2114 
2115  CStringList command(stringOps::splitSpace(docBrowser));
2116 
2117  Info
2118  << "OpenFOAM " << foamVersion::api << " documentation:" << nl
2119  << " " << command << nl << endl;
2120 
2121  Foam::system(command, true);
2122 }
2123 
2124 
2125 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
2126 {
2127  bool ok = true;
2128 
2129  if (Pstream::master())
2130  {
2131  const label nargs = args_.size()-1;
2132  if (checkArgs && nargs != validArgs.size())
2133  {
2134  FatalError
2135  << "Expected " << validArgs.size()
2136  << " arguments but found " << nargs << endl;
2137  ok = false;
2138  }
2139 
2140  if (checkOpts)
2141  {
2142  forAllConstIters(options_, iter)
2143  {
2144  const word& optName = iter.key();
2145  if
2146  (
2147  !validOptions.contains(optName)
2148  && !validParOptions.contains(optName)
2149  )
2150  {
2151  FatalError
2152  << "Invalid option: -" << optName << endl;
2153  ok = false;
2154  }
2155  }
2156  }
2157 
2158  if (!ok)
2159  {
2160  FatalError
2161  << nl
2162  << "See '" << executable_ << " -help' for usage" << nl
2163  << " or '" << executable_
2164  << " -help-full' for extended usage" << nl
2165  << nl;
2166  }
2167  }
2168 
2169  return ok;
2170 }
2171 
2172 
2173 bool Foam::argList::checkRootCase() const
2174 {
2175  if (!fileHandler().isDir(rootPath()))
2176  {
2177  FatalError
2178  << executable_
2179  << ": cannot open root directory " << rootPath()
2180  << endl;
2181 
2182  return false;
2183  }
2184 
2185  const fileName pathDir(fileHandler().filePath(path(), false));
2186 
2187  if (checkProcessorDirectories_ && pathDir.empty() && Pstream::master())
2188  {
2189  // Allow non-existent processor directories on sub-processes,
2190  // to be created later (e.g. redistributePar)
2191  FatalError
2192  << executable_
2193  << ": cannot open case directory " << path()
2194  << endl;
2195 
2196  return false;
2197  }
2198 
2199  return true;
2200 }
2201 
2202 
2203 // ************************************************************************* //
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:567
static bool floatTransfer
Should compact transfer be used in which floats replace doubles reducing the bandwidth requirement at...
Definition: UPstream.H:366
static const word & myWorld()
My world.
Definition: UPstream.H:1120
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:2166
void printBuildInfo(std::ostream &os, const bool full=true)
Print information about version, build, arch to output stream.
static refPtr< fileOperation > fileHandlerPtr_
The currently active file handler. Avoid accessing directly.
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:547
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void setNamedValue(std::string name, int val, bool report=false)
Set named value, but also handle embedded &#39;name=value&#39; syntax.
A class for handling file names.
Definition: fileName.H:71
static const Enum< commsTypes > commsTypeNames
Enumerated names for the communication types.
Definition: UPstream.H:84
static void setAdvanced(const word &optName, bool advanced=true)
Set an existing option as being &#39;advanced&#39; or normal.
Definition: argList.C:404
labelList findMatchingStrings(const UnaryMatchPredicate &matcher, const UList< StringType > &input, const bool invert=false)
Extract list indices for all matches.
static std::string::size_type usageMin
Min indentation when displaying usage (default: 20)
Definition: argList.H:294
static word postProcessOptionName
Standard name for the post-processing option.
Definition: argList.H:304
static void noMandatoryArgs()
Flag command arguments as being optional (non-mandatory)
Definition: argList.C:479
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
bool unsetOption(const word &optName)
Unset option directly (use with caution)
Definition: argList.C:2023
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:331
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
static void set(bool verbose=false)
Activate SIGSEGV signal handler.
Definition: sigSegv.C:66
Template class for non-intrusive linked lists.
Definition: LList.H:46
int infoDetailLevel
Global for selective suppression of Info output.
pid_t ppid()
Return the parent PID of this process.
Definition: POSIX.C:320
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
static const fileName null
An empty fileName.
Definition: fileName.H:110
static int nProcsSimpleSum
Number of processors to change from linear to tree communication.
Definition: UPstream.H:371
std::ostream & stdStream()
Return std::ostream for output operations.
static SLList< string > notes
General usage notes.
Definition: argList.H:289
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static Ostream & writeDivider(Ostream &os)
Write the standard file section divider.
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1004
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:198
void incrVerbose(int level=1) noexcept
Increase the verbosity level.
Definition: parRun.H:138
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
static void noParallel()
Remove the parallel options.
Definition: argList.C:584
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:245
static void addOptionCompat(const word &optName, std::pair< const char *, int > compat)
Specify an alias for the option name.
Definition: argList.C:418
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
static bool printRootsSubscription(const UList< string > &hostProcs, const UList< fileName > &roots)
Definition: argList.C:248
bool patched()
Test if the patch string appears to be in use, which is when it is defined (non-zero).
static HashTable< std::pair< word, int > > validOptionsCompat
A list of aliases for options.
Definition: argList.H:267
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:637
static bool postProcess(int argc, char *argv[])
True if the post-processing option is found in the argv list.
Definition: argList.C:608
Operations on lists of strings.
static void set(bool verbose=false)
Activate SIGINT signal handler.
Definition: sigInt.C:65
simpleObjectRegistry & debugObjects()
Access to registered DebugSwitch objects.
Definition: debug.C:288
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:339
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1029
static HashTable< string, label, Hash< label > > argUsage
Short description for program arguments.
Definition: argList.H:279
void runPar(int &argc, char **&argv)
Initialize UPstream for a parallel run.
Definition: parRun.H:209
List< string > stringList
List of string.
Definition: stringList.H:32
int infoSwitch(const char *name, const int deflt=0)
Lookup info switch or add default value.
Definition: debug.C:228
static std::string date()
The current wall-clock date as a string formatted as (MON dd yyyy), where MON is Jan, Feb, etc.
Definition: clock.C:73
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:453
virtual ~argList()
Destructor.
Definition: argList.C:1930
static int tuning_NBX_
Tuning parameters for non-blocking exchange (NBX)
Definition: UPstream.H:397
bool allowFunctionObjects() const
The controlDict &#39;functions&#39; entry is allowed to be used.
Definition: argList.C:1941
static bool warnAboutAge(const int version) noexcept
Test if an age warning should be emitted.
Definition: error.C:51
simpleObjectRegistry & optimisationObjects()
Access to registered OptimisationSwitch objects.
Definition: debug.C:310
static void printHostsSubscription(const UList< string > &hostProcs)
Definition: argList.C:212
static void set(bool verbose=false)
Activate SIGFPE signal handler when FOAM_SIGFPE is set.
Definition: sigFpe.C:176
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
static void disable() noexcept
Disallow JobInfo by forcing writeJobInfo (InfoSwitch) off.
Definition: JobInfo.C:88
void parse(bool checkArgs, bool checkOpts, bool initialise)
Scan for -help, -doc options etc prior to checking the validity of other args/opts and finally initia...
Definition: argList.C:1179
constexpr const char *const group
Group name for atomic constants.
static void removeOption(const word &optName)
Remove option from validOptions and from optionUsage.
Definition: argList.C:471
static autoPtr< fileOperationInitialise > New(const word &type, int &argc, char **&argv)
Select initialisation type.
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
static int nProcsNonblockingExchange
Number of processors to change to nonBlocking consensual exchange (NBX). Ignored for zero or negative...
Definition: UPstream.H:377
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
bool allowLibs() const
The controlDict &#39;libs&#39; entry is allowed to be used. (eg, has not been disabled by the -no-libs option...
Definition: argList.C:1959
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:2044
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
static const char * name(const bool b) noexcept
A string representation of bool as "false" / "true".
Definition: Switch.C:141
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1020
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:382
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
Definition: UPstream.C:55
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:260
"scheduled" : (MPI_Send, MPI_Recv)
static bool bannerEnabled()
Banner status (enabled/disabled).
Definition: argList.C:497
A class for handling words, derived from Foam::string.
Definition: word.H:63
static void addDryRunOption(const string &usage, bool advanced=false)
Enable a &#39;dry-run&#39; bool option, with usage information.
Definition: argList.C:504
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
static Istream & input(Istream &is, IntRange< T > &range)
Definition: IntRanges.C:47
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1014
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:193
void write() const
Write job info to its file in the "running" jobs directory.
Definition: JobInfo.C:210
virtual void write(Ostream &os, const bool withTitle=true) const
Print error message.
Definition: error.C:339
static int maxFileModificationPolls
Max number of times to poll for file modification changes.
Definition: IOobject.H:336
Reading is optional [identical to LAZY_READ].
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
string userName()
Return the user&#39;s login name.
Definition: POSIX.C:422
static std::string::size_type usageMax
Max screen width when displaying usage (default: 80)
Definition: argList.H:299
static std::string clockTime()
The current wall-clock (in local time) as a string formatted as as (hh:mm:ss).
Definition: clock.C:88
static void ignoreOptionCompat(std::pair< const char *, int > compat, bool expectArg)
Specify an option to be ignored.
Definition: argList.C:432
static HashTable< string > optionUsage
Short description for validOptions.
Definition: argList.H:284
String literal.
Definition: keyType.H:82
static void noLibs()
Add the &#39;-no-libs&#39; command line option.
Definition: argList.C:573
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:68
#define DetailInfo
Definition: evalEntry.C:30
static void noCheckProcessorDirectories()
Disable checking of processor directories.
Definition: argList.C:602
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:99
string hostName()
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:371
const int api
OpenFOAM api number (integer) corresponding to the value of OPENFOAM at the time of compilation...
pid_t pid()
Return the PID of this process.
Definition: POSIX.C:314
static HashTable< std::pair< bool, int > > ignoreOptionsCompat
A list of options to ignore.
Definition: argList.H:274
bool threads() const noexcept
True if MPI threads are desired (default: false)
Definition: parRun.H:193
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:520
static HashSet< string > advancedOptions
The "advanced" options are shown with -help-full (not with –help)
Definition: argList.H:250
static const Enum< fileCheckTypes > fileCheckTypesNames
Names for the fileCheckTypes.
Definition: IOobject.H:202
simpleObjectRegistry & infoObjects()
Access to registered InfoSwitch objects.
Definition: debug.C:299
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
dlLibraryTable & libs() const noexcept
Mutable access to the loaded dynamic libraries.
Definition: argListI.H:133
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:326
bool append(const fileName &libName)
Add to the list of names, but do not yet open.
static void check(const int retVal, const char *what)
static fileName envRelativePath(const fileName &input, const bool caseTag=false)
Return the input relative to the globalPath by stripping off a leading value of the envGlobalPath...
Definition: argList.C:658
static autoPtr< fileOperation > New(const word &handlerType, bool verbose=false)
Select fileHandler-type. Uses defaultFileHandler if the handlerType is empty.
pid_t pgid()
Return the group PID of this process.
Definition: POSIX.C:326
static void set(bool verbose=false)
Activate SIGQUIT signal handler.
Definition: sigQuit.C:66
Foam::SubStrings< StringType > splitSpace(const StringType &str)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional &#39;FOAM Warning&#39; header text...
static word envExecutable()
Name of the executable from environment variable.
Definition: argList.C:645
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: POSIX.C:877
const std::string buildArch
OpenFOAM build architecture information (machine endian, label/scalar sizes) as a std::string...
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:387
const std::string version
OpenFOAM version (name or stringified number) as a std::string.
static void parallelThreads_on()
MPI threads are desired for the application.
Definition: argList.C:596
void stop()
Job end with "normal" termination.
Definition: JobInfo.C:228
static fileName envGlobalPath()
Global case (directory) from environment variable.
Definition: argList.C:651
static word defaultFileHandler
Name of the default fileHandler.
static bool argsMandatory()
Command arguments type (optional/mandatory).
Definition: argList.C:485
bool setOption(const word &optName, const string &param="")
Set option directly (use with caution)
Definition: argList.C:1995
static fileName validate(const std::string &, const bool doClean=true)
Construct fileName without invalid characters, possibly applying other transformations such as changi...
Definition: fileName.C:199
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1037
static int algorithm
Preferred exchange algorithm (may change or be removed in future)
meshDefDict readIfPresent("polyMeshPatches", polyPatchNames)
const std::string patch
OpenFOAM patch number as a std::string.
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
fileName cwd()
The physical or logical current working directory path name.
Definition: POSIX.C:590
JobInfo jobInfo
Definition: JobInfo.C:45
messageStream Info
Information stream (stdout output on master, null elsewhere)
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:491
static Ostream & writeBanner(Ostream &os, const bool noSyntaxHint=false)
Write the standard OpenFOAM file/dictionary banner.
static const fileOperation & fileHandler()
Return the current file handler. Will create the default file handler if necessary.
bool parRun() const noexcept
True if this is (or will be) a parallel run.
Definition: parRun.H:156
List< label > labelList
A List of labels.
Definition: List.H:62
static rangeType subProcs(const label communicator=worldComm)
Range of process indices for sub-processes.
Definition: UPstream.H:1140
const std::string build
OpenFOAM build information as a std::string.
int system(const std::string &command, const bool bg=false)
Execute the specified command via the shell.
Definition: POSIX.C:1702
static void addUsage(const word &optName, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:446
static const wordList & allWorlds() noexcept
All worlds.
Definition: UPstream.H:1096
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
List< fileName > fileNameList
List of fileName.
Definition: fileNameList.H:32
argList(int &argc, char **&argv, bool checkArgs=argList::argsMandatory(), bool checkOpts=true, bool initialise=true)
Construct from argc and argv checking the arguments and options as requested.
Definition: argList.C:896
Foam::argList args(argc, argv)
dictionary & controlDict()
The central control dictionary, the contents of which are either taken directly from the FOAM_CONTROL...
Definition: debug.C:142
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:570
label count(const UList< word > &optionNames) const
Return how many of the specified options were used.
Definition: argList.C:1967
static HashTable< string > validOptions
A list of valid options.
Definition: argList.H:255
int verbose() const noexcept
Return the verbose flag.
Definition: argListI.H:121
bool setEnv(const word &name, const std::string &value, const bool overwrite)
Set an environment variable, return true on success.
Definition: POSIX.C:356
bool check(bool checkArgs=argList::argsMandatory(), bool checkOpts=true) const
Check the parsed command-line for mandatory arguments and that all the options are correct...
Definition: argList.C:2118
void incrDryRun(int level=1) noexcept
Increase the dry-run level.
Definition: parRun.H:118
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
string expand(const std::string &s, const HashTable< string > &mapping, const char sigil='$')
Expand occurrences of variables according to the mapping and return the expanded string.
Definition: stringOps.C:704
readOption
Enumeration defining read preferences.