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