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-2025 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 #include "Field.H" // Ugly handling of localBoundaryConsistency switches
51 
52 #include <cctype>
53 
54 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
55 
56 bool Foam::argList::argsMandatory_ = true;
57 bool Foam::argList::checkProcessorDirectories_ = true;
58 bool Foam::argList::parallelThreads_ = false;
59 
71 
74 
75 Foam::argList::initValidTables::initValidTables()
76 {
77  argList::addOption
78  (
79  "case",
80  "dir",
81  "Case directory (instead of current directory)"
82  );
83  argList::addOption
84  (
85  "lib",
86  "name",
87  "Additional library or library list to load.\n"
88  "[Can be used multiple times]",
89  true // advanced option
90  );
91  argList::addBoolOption
92  (
93  "no-libs",
94  "Disable use of the controlDict 'libs' entry",
95  true // advanced option
96  );
97 
98  argList::addOption
99  (
100  "debug-switch",
101  "name=val",
102  "Set named DebugSwitch (default value: 1).\n"
103  "[Can be used multiple times]",
104  true // advanced option
105  );
106 
107  argList::addOption
108  (
109  "info-switch",
110  "name=val",
111  "Set named InfoSwitch (default value: 1).\n"
112  "[Can be used multiple times]",
113  true // advanced option
114  );
115 
116  argList::addOption
117  (
118  "opt-switch",
119  "name=val",
120  "Set named OptimisationSwitch (default value: 1).\n"
121  "[Can be used multiple times]",
122  true // advanced option
123  );
124 
125  argList::addBoolOption("parallel", "Run in parallel");
126  validParOptions.set("parallel", "");
127 
128  argList::addBoolOption
129  (
130  "mpi-threads",
131  "Request use of MPI threads",
132  true // advanced option
133  );
134 
135  argList::addBoolOption
136  (
137  "mpi-no-comm-dup",
138  "Disable initial MPI_Comm_dup()",
139  true // advanced option
140  );
141 
142  argList::addOption
143  (
144  "roots",
145  "(dir1 .. dirN)",
146  "Subprocess root directories for distributed running",
147  true // advanced option
148  );
149  validParOptions.set
150  (
151  "roots",
152  "(dir1 .. dirN)"
153  );
154 
155  argList::addOption
156  (
157  "decomposeParDict",
158  "file",
159  "Alternative decomposePar dictionary file"
160  );
161  argList::addOption
162  (
163  "hostRoots",
164  "((host1 dir1) .. (hostN dirN))",
165  "Per-subprocess root directories for distributed running."
166  " The host specification can be a regex.",
167  true // advanced option
168  );
169  validParOptions.set
170  (
171  "hostRoots",
172  "((host1 dir1) .. (hostN dirN))"
173  );
174 
175  argList::addBoolOption
176  (
177  "noFunctionObjects",
178  "Do not execute function objects",
179  true // advanced option
180  );
181 
182  argList::addOption
183  (
184  "fileHandler",
185  "handler",
186  "Override the file handler type",
187  true // advanced option
188  );
189 
190  argList::addOption
191  (
192  "world",
193  "name",
194  "Name of the local world for parallel communication",
195  true // advanced option
196  );
197  validParOptions.set
198  (
199  "world",
200  "name"
201  );
202 
203  argList::addBoolOption
204  (
205  "mpi-split-by-appnum",
206  "Split world communicator based on the APPNUM",
207  true // advanced option
208  );
209 
210  // Some standard option aliases (with or without version warnings)
211 // argList::addOptionCompat
212 // (
213 // "noFunctionObjects", {"no-function-objects", 0}
214 // );
215 
216  Pstream::addValidParOptions(validParOptions);
217 }
218 
219 Foam::argList::initValidTables dummyInitValidTables;
220 
221 
222 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
223 
224 namespace Foam
225 {
227 // Counted per machine name
228 // Does not include any sorting since we wish to know the ordering according to
229 // mpi rank.
230 //
231 // Always include the master too.
232 // This provides a better overview of the subscription
233 static void printHostsSubscription(const UList<string>& hostProcs)
234 {
235  Info<< "Hosts :\n(" << nl;
236 
237  std::string prev = Foam::hostName();
238  int count = 1;
239 
240  for (const auto& str : hostProcs)
241  {
242  std::string curr(str.substr(0, str.rfind('.')));
243 
244  if (prev != curr)
245  {
246  if (count)
247  {
248  // Finish previous
249  Info<< " (" << prev.c_str() << ' ' << count << ')' << nl;
250  count = 0;
251  }
252 
253  prev = std::move(curr);
254  }
255  ++count;
256  }
257 
258  if (count)
259  {
260  // Finished last one
261  Info<< " (" << prev.c_str() << ' ' << count << ')' << nl;
262  }
263 
264  Info<< ')' << nl;
265 }
266 
267 
268 static bool printRootsSubscription
269 (
270  const UList<string>& hostProcs,
271  const UList<fileName>& roots
272 )
273 {
274  if (hostProcs.size() == roots.size()+1)
275  {
276  // Sort roots according to hostProc
277  DynamicList<string> sortedProcs;
278  DynamicList<label> sortedRoots;
279 
280  forAll(roots, i)
281  {
282  const fileName& root = roots[i];
283  const string& host = hostProcs[i+1];
284  const label index = sortedProcs.find(host);
285 
286  if (index == -1)
287  {
288  sortedProcs.push_back(host);
289  sortedRoots.push_back(i);
290  }
291  else if (roots[sortedRoots[index]] != root)
292  {
293  // Not properly sorted...
294  return false;
295  }
296  }
297 
298  Info<< "Roots :\n(" << nl;
299  forAll(sortedProcs, i)
300  {
301  Info<< " (" << sortedProcs[i].c_str() << ' '
302  << roots[sortedRoots[i]] << ')' << nl;
303  }
304  Info<< ')' << nl;
305 
306  return true;
307  }
308 
309  return false;
310 }
311 
312 } // End namespace Foam
313 
314 
315 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
316 
317 void Foam::argList::checkITstream(const ITstream& is, const label index)
318 {
319  const label remaining = is.nRemainingTokens();
320 
321  if (remaining)
322  {
323  std::cerr
324  << nl
325  << "--> FOAM WARNING:" << nl
326  << "Argument " << index << " has "
327  << remaining << " excess tokens" << nl << nl;
328  }
329  else if (!is.size())
330  {
331  std::cerr
332  << nl
333  << "--> FOAM WARNING:" << nl
334  << "Argument " << index << " had no tokens" << nl << nl;
335  }
336 }
337 
338 
339 void Foam::argList::checkITstream(const ITstream& is, const word& optName)
340 {
341  const label remaining = is.nRemainingTokens();
342 
343  if (remaining)
344  {
345  std::cerr
346  << nl
347  << "--> FOAM WARNING:" << nl
348  << "Option -" << optName << " has "
349  << remaining << " excess tokens" << nl << nl;
350  }
351  else if (!is.size())
352  {
353  std::cerr
354  << nl
355  << "--> FOAM WARNING:" << nl
356  << "Option -" << optName << " had no tokens" << nl << nl;
357  }
358 }
359 
360 
361 void Foam::argList::raiseBadInput(const word& optName) const
362 {
363  // Can use FatalError
364  // predicate checks are not used at the earliest stages
365  FatalErrorIn(executable())
366  << "Option -" << optName << " with invalid input" << nl
367  << exit(FatalError);
368 }
369 
370 
372 (
373  const string& argName,
374  const string& usage
375 )
376 {
377  validArgs.push_back(argName);
378 
379  // The first program argument starts at 1 - obtain index after push_back()
380 
381  const label index = validArgs.size();
382 
383  if (usage.empty())
384  {
385  argUsage.erase(index);
386  }
387  else
388  {
389  argUsage.set(index, usage);
390  }
391 }
392 
393 
395 (
396  const word& optName,
397  const string& usage,
398  bool advanced
399 )
400 {
401  argList::addOption(optName, "", usage, advanced);
402 }
403 
404 
406 (
407  const word& optName,
408  const string& param,
409  const string& usage,
410  bool advanced
411 )
412 {
413  validOptions.set(optName, param);
414  if (!usage.empty())
415  {
416  optionUsage.set(optName, usage);
417  }
418  if (advanced)
419  {
420  advancedOptions.set(optName);
421  }
422 }
423 
424 
425 void Foam::argList::setAdvanced(const word& optName, bool advanced)
426 {
427  if (advanced && validOptions.contains(optName))
428  {
429  advancedOptions.set(optName);
430  }
431  else
432  {
433  advancedOptions.erase(optName);
434  }
435 }
436 
437 
439 (
440  const word& optName,
441  std::pair<const char*,int> compat
442 )
443 {
444  validOptionsCompat.insert
445  (
446  compat.first,
447  std::pair<word,int>(optName, compat.second)
448  );
449 }
450 
451 
453 (
454  std::pair<const char*,int> compat,
455  bool expectArg
456 )
457 {
458  ignoreOptionsCompat.insert
459  (
460  compat.first,
461  std::pair<bool,int>(expectArg, compat.second)
462  );
463 }
464 
465 
467 (
468  const word& optName,
469  const string& usage
470 )
471 {
472  if (usage.empty())
473  {
474  optionUsage.erase(optName);
475  }
476  else
477  {
478  optionUsage.set(optName, usage);
479  }
480 }
481 
482 
483 void Foam::argList::addNote(const string& note)
484 {
485  if (!note.empty())
486  {
487  notes.push_back(note);
488  }
489 }
490 
491 
492 void Foam::argList::removeOption(const word& optName)
493 {
494  validOptions.erase(optName);
495  optionUsage.erase(optName);
496  advancedOptions.erase(optName);
497 }
498 
501 {
502  argsMandatory_ = false;
503 }
504 
507 {
508  return argsMandatory_;
509 }
510 
513 {
515 }
516 
517 
519 {
520  return (::Foam::infoDetailLevel > 0);
521 }
522 
523 
525 (
526  const string& usage,
527  bool advanced
528 )
529 {
530  const word optName("dry-run", false);
531 
532  argList::addBoolOption(optName, usage, advanced);
533  if (!advanced)
534  {
535  advancedOptions.erase(optName); // Avoid 'stickiness'
536  }
537 }
538 
539 
541 (
542  const string& usage,
543  bool advanced
544 )
545 {
546  const word optName("verbose", false);
547 
548  if (usage.empty())
549  {
551  (
552  optName,
553  "Additional verbosity (can be used multiple times)",
554  advanced
555  );
556  }
557  else
558  {
559  argList::addBoolOption(optName, usage, advanced);
560  }
561  if (!advanced)
562  {
563  advancedOptions.erase(optName); // Avoid 'stickiness'
564  }
565 }
566 
567 
568 void Foam::argList::noFunctionObjects(bool addWithOption)
569 {
570  removeOption("noFunctionObjects");
571 
572  // Ignore this bool option without warning
573  // - cannot tie to any particular version anyhow
574  ignoreOptionCompat({"noFunctionObjects", 0}, false);
575 
576  if (addWithOption)
577  {
579  (
580  "withFunctionObjects",
581  "Execute functionObjects"
582  // An advanced option, but seldom used so expose it more
583  );
584  }
585 }
586 
589 {
591 }
592 
593 
595 {
597  (
598  "no-libs",
599  "Disable use of the controlDict libs entry",
600  true // advanced option
601  );
602 }
603 
604 
606 {
607  removeOption("parallel");
608  removeOption("roots");
609  removeOption("decomposeParDict");
610  removeOption("hostRoots");
611  removeOption("world");
612  removeOption("mpi-threads");
613  removeOption("mpi-no-comm-dup");
614  removeOption("mpi-split-by-appnum");
615  validParOptions.clear();
616 }
617 
620 {
621  parallelThreads_ = true;
622 }
623 
626 {
627  checkProcessorDirectories_ = false;
628 }
629 
630 
631 bool Foam::argList::postProcess(int argc, char *argv[])
632 {
633  for (int argi = 1; argi < argc; ++argi)
634  {
635  const char *optName = argv[argi];
636 
637  if (optName[0] == '-')
638  {
639  ++optName; // Looks like an option, skip leading '-'
640 
641  if (optName == postProcessOptionName)
642  {
643  return true;
644  }
645  }
646  }
647 
648  return false;
649 }
650 
651 
652 int Foam::argList::verbose(int argc, char *argv[])
653 {
654  int num = 0;
655  for (int argi = 1; argi < argc; ++argi)
656  {
657  if (strcmp(argv[argi], "-verbose") == 0)
658  {
659  ++num;
660  }
661  }
662  return num;
663 }
664 
665 
666 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
669 {
670  return Foam::getEnv("FOAM_EXECUTABLE");
671 }
672 
673 
675 {
676  return Foam::getEnv("FOAM_CASE");
677 }
678 
679 
681 (
682  const fileName& input,
683  const bool caseTag
684 )
685 {
686  if (input.isAbsolute())
687  {
688  return input.relative(envGlobalPath(), caseTag);
689  }
690 
691  return input;
692 }
693 
694 
695 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
696 
697 Foam::word Foam::argList::optionCompat(const word& optName)
698 {
699  // NB: optName includes the leading '-' so that the return value
700  // can be used directly
701 
702  if (!validOptionsCompat.empty())
703  {
704  const auto fnd = validOptionsCompat.cfind(optName.substr(1));
705 
706  if (fnd.good())
707  {
708  const auto& alt = fnd.val();
709 
710  // No error::master() guard - only called on master anyhow
711  if (error::warnAboutAge(alt.second))
712  {
713  std::cerr
714  << "--> FOAM IOWarning :" << nl
715  << " Found [v" << alt.second << "] '"
716  << optName << "' instead of '-"
717  << alt.first << "' option"
718  << nl
719  << std::endl;
720 
721  error::warnAboutAge("option", alt.second);
722  }
723 
724  return "-" + alt.first;
725  }
726  }
727 
728  // Nothing found - pass through the original input
729  return optName;
730 }
731 
732 
733 int Foam::argList::optionIgnore(const word& optName)
734 {
735  // NB: optName is without the leading '-'
736 
737  if (!ignoreOptionsCompat.empty())
738  {
739  const auto fnd = ignoreOptionsCompat.cfind(optName);
740 
741  if (fnd.good())
742  {
743  const auto& alt = fnd.val();
744 
745  // Number to skip (including the option itself)
746  // '-option ARG' or '-option'
747  const int nskip = (alt.first ? 2 : 1);
748 
749  // No error::master() guard - only called on master anyhow
750  if (error::warnAboutAge(alt.second))
751  {
752  std::cerr
753  << "--> FOAM IOWarning :" << nl
754  << " Ignoring [v" << alt.second << "] '-"
755  << optName << (nskip > 1 ? " ARG" : "")
756  << "' option"
757  << nl
758  << std::endl;
759 
760  error::warnAboutAge("option", alt.second);
761  }
762 
763  return nskip;
764  }
765  }
766 
767  // TBD: could ignore -verbose, -dry-run etc if they are not active...
768 
769  return 0; // Do not skip
770 }
771 
772 
773 bool Foam::argList::regroupArgv(int& argc, char**& argv)
774 {
775  int nArgs = 1;
776  int ignore = 0;
777  unsigned depth = 0;
778  string group; // For grouping ( ... ) arguments
779 
780  // Note: we rewrite directly into args_
781  // and use a second pass to sort out args/options
782 
783  args_[0] = fileName(argv[0]);
784  for (int argi = 1; argi < argc; ++argi)
785  {
786  const char *optName = argv[argi];
787 
788  if (optName[0] == '(' && optName[1] == '\0')
789  {
790  // Begin list
791  ++depth;
792  group += '(';
793  }
794  else if (optName[0] == ')' && optName[1] == '\0')
795  {
796  if (depth)
797  {
798  // End list
799  --depth;
800  group += ')';
801  if (!depth)
802  {
803  args_[nArgs++] = group;
804  group.clear();
805  }
806  }
807  else
808  {
809  // A stray ')' - likely never happens
810  args_[nArgs++] = argv[argi];
811  }
812  }
813  else if (depth)
814  {
815  // Quote each string element
816  group += '"';
817  group += argv[argi];
818  group += '"';
819  }
820  else if (optName[0] == '-')
821  {
822  ++optName; // Looks like an option, skip leading '-'
823 
824  if (validOptions.contains(optName))
825  {
826  // Known option name
827  args_[nArgs++] = argv[argi];
828  }
829  else if ((ignore = optionIgnore(optName)) > 0)
830  {
831  // Option to be ignored (with/without an argument)
832  if (ignore > 1)
833  {
834  ++argi;
835  }
836  }
837  else
838  {
839  // Try alias for the option name
840  args_[nArgs++] = optionCompat(argv[argi]);
841  }
842  }
843  else
844  {
845  args_[nArgs++] = argv[argi];
846  }
847  }
848 
849  if (group.size())
850  {
851  // Group(s) not closed, but flush anything still pending
852  args_[nArgs++] = group;
853  }
854 
855  args_.resize(nArgs);
856 
857  std::string::size_type len = (nArgs-1); // Spaces between args
858  for (const auto& s : args_)
859  {
860  len += s.length();
861  }
862 
863  // Length needed for regrouped command-line
864  commandLine_.reserve(len);
865 
866  return nArgs < argc;
867 }
868 
869 
870 void Foam::argList::setCasePaths()
871 {
872  fileName caseDir;
873 
874  const auto optIter = options_.cfind("case"); // [-case dir] specified?
875 
876  if (optIter.good())
877  {
878  caseDir = fileName::validate(optIter.val()); // includes 'clean'
879 
880  if (caseDir.empty() || caseDir == ".")
881  {
882  // Treat "", "." and "./" as if -case was not specified
883  caseDir = cwd();
884  options_.erase("case");
885  }
886  else
887  {
888  caseDir.expand();
889  caseDir.toAbsolute();
890  }
891  }
892  else
893  {
894  // Nothing specified, use the current dir
895  caseDir = cwd();
896  }
897 
898  // The caseDir is a cleaned, absolute path
899 
900  rootPath_ = caseDir.path();
901  globalCase_ = caseDir.name();
902  case_ = globalCase_; // The (processor) local case name
903 
904  // OPENFOAM API
905  setEnv("FOAM_API", std::to_string(foamVersion::api), true);
906 
907  // Global case (directory) and case-name as environment variables
908  setEnv("FOAM_CASE", caseDir, true);
909  setEnv("FOAM_CASENAME", globalCase_, true);
910 
911  // Executable name, unless already present in the environment
912  setEnv("FOAM_EXECUTABLE", executable_, false);
913 }
914 
915 
916 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
917 
919 (
920  int& argc,
921  char**& argv,
922  bool checkArgs,
923  bool checkOpts,
924  bool initialise
925 )
926 :
927  runControl_(),
928  args_(argc),
929  options_(argc),
930  libs_()
931 {
932  // Pre-scan for some options needed for initial setup:
933  // -fileHandler (takes an argument)
934  // -mpi-threads (bool option)
935  // -debug-switch, -info-switch, -opt-switch
936  // so their values can also influence the initial setup
937  //
938  // Also handle -dry-run and -verbose counting
939  // (it is left to the application to decide what to do with them).
940  // Detect any parallel run options
941 
942  word fileHandlerName;
943 
944  if (parallelThreads_)
945  {
946  // Default -mpi-threads configured statically from application
947  runControl_.threads(true);
948  }
949 
950  for (int argi = 1; argi < argc; ++argi)
951  {
952  const char *optName = argv[argi];
953 
954  if (optName[0] == '-')
955  {
956  ++optName; // Looks like an option, skip leading '-'
957  bool emitErrorMessage = false;
958 
959  if (strcmp(optName, "dry-run") == 0)
960  {
961  runControl_.incrDryRun();
962  }
963  else if (strcmp(optName, "verbose") == 0)
964  {
965  runControl_.incrVerbose();
966  }
967  else if (strcmp(optName, "mpi-threads") == 0)
968  {
969  runControl_.threads(true);
970  }
971  else if (strcmp(optName, "fileHandler") == 0)
972  {
973  // Requires a parameter
974  if (argi < argc-1)
975  {
976  ++argi;
977  fileHandlerName = argv[argi];
978  }
979  else
980  {
981  emitErrorMessage = true;
982  }
983  }
984  else if (strcmp(optName, "debug-switch") == 0)
985  {
986  // The '-debug-switch' option:
987  // change registered debug switch
988  if (argi < argc-1)
989  {
990  ++argi;
992  .setNamedValue(argv[argi], 1); // silent
993  }
994  else
995  {
996  // emit error on the second pass
997  }
998  }
999  else if (strcmp(optName, "info-switch") == 0)
1000  {
1001  // The '-info-switch' option:
1002  // change registered info switch
1003  if (argi < argc-1)
1004  {
1005  ++argi;
1006  DetailInfo << "info-switch ";
1008  .setNamedValue(argv[argi], 1); // silent
1009  }
1010  else
1011  {
1012  // emit error on the second pass
1013  }
1014  }
1015  else if (strcmp(optName, "opt-switch") == 0)
1016  {
1017  // The '-opt-switch' option:
1018  // change registered optimisation switch
1019  if (argi < argc-1)
1020  {
1021  ++argi;
1022  DetailInfo << "opt-switch ";
1024  .setNamedValue(argv[argi], 1); // silent
1025  }
1026  else
1027  {
1028  // emit error on the second pass
1029  }
1030  }
1031  else if (validParOptions.contains(optName))
1032  {
1033  // Contains a parallel run option
1034  runControl_.parRun(true);
1035  }
1036 
1037  if (emitErrorMessage)
1038  {
1039  // Missing argument: emit message but not exit or
1040  // FatalError since Pstream etc are not yet initialised
1041 
1042  Info<< nl
1043  << "Error: option '-" << optName
1044  << "' requires an argument" << nl << nl;
1045  }
1046  }
1047  }
1048 
1049  // No -fileHandler specifed, get from environment or use default
1050  if (fileHandlerName.empty())
1051  {
1052  fileHandlerName = Foam::getEnv("FOAM_FILEHANDLER");
1053  if (fileHandlerName.empty())
1054  {
1055  fileHandlerName = fileOperation::defaultFileHandler;
1056  }
1057  }
1058 
1059  // Parse out any additional fileHandler-specific options
1060  // (may alter argv list). Recover its threading requirements
1061  {
1062  auto fileOperationInit = fileOperations::fileOperationInitialise::New
1063  (
1064  fileHandlerName,
1065  argc,
1066  argv
1067  );
1068 
1069  if (fileOperationInit && fileOperationInit->needsThreading())
1070  {
1071  runControl_.threads(true);
1072  }
1073  }
1074 
1075  // Parallel job options detected?
1076  // - start parallel run (possibly filters argv as a side-effect)
1077  if (runControl_.parRun())
1078  {
1079  runControl_.runPar(argc, argv);
1080  }
1081 
1082  // addProfiling(argList, "argList");
1083 
1084  // ------------------------------------------------------------------------
1085 
1086  // Convert argv -> args_ and capture ( ... ) lists
1087  regroupArgv(argc, argv);
1088  commandLine_ += args_[0];
1089 
1090  // Set executable name immediately - useful when emitting errors.
1091  executable_ = fileName(args_[0]).name();
1092 
1093  // Check arguments and options, argv[0] was already handled
1094  int nArgs = 1;
1095  for (int argi = 1; argi < args_.size(); ++argi)
1096  {
1097  commandLine_ += ' ';
1098  commandLine_ += args_[argi];
1099 
1100  const char *optName = args_[argi].data();
1101 
1102  if (optName[0] == '-')
1103  {
1104  ++optName; // Looks like an option, skip leading '-'
1105 
1106  if (!*optName)
1107  {
1108  Warning
1109  << "Ignoring lone '-' on the command-line" << endl;
1110  continue;
1111  }
1112 
1113  // Option known and expects an argument?
1114  // - use Switch for a tri-state
1115  // True : known option, expects a parameter
1116  // False : known option, no parameter
1117  // bad() : unknown option
1118 
1119  Switch wantArg(Switch::INVALID);
1120  auto optIter = validOptions.cfind(optName);
1121  if
1122  (
1123  optIter.good()
1124  || (optIter = validParOptions.cfind(optName)).good()
1125  )
1126  {
1127  wantArg = !optIter.val().empty();
1128  }
1129 
1130 
1131  if (wantArg)
1132  {
1133  // Option expects a parameter
1134  // - get it or emit a FatalError.
1135 
1136  ++argi;
1137  if (argi >= args_.size())
1138  {
1140 
1141  Info<< nl
1142  <<"Error: option '-" << optName
1143  << "' requires an argument" << nl << nl
1144  << "See '" << executable_ << " -help' for usage" << nl
1145  << " or '" << executable_
1146  << " -help-full' for extended usage" << nl
1147  << nl;
1148 
1149  UPstream::exit(1); // works for serial and parallel
1150  }
1151 
1152  commandLine_ += ' ';
1153  commandLine_ += args_[argi];
1154 
1155  //
1156  // Special handling of these options
1157  //
1158 
1159  if (strcmp(optName, "lib") == 0)
1160  {
1161  // The '-lib' option:
1162  // Add name(s) to libs for later opening
1163  libs().push_back(this->getList<fileName>(argi));
1164  }
1165  else if (strcmp(optName, "debug-switch") == 0)
1166  {
1167  // The '-debug-switch' option:
1168  // dryrun reporting only (already set above)
1169  DetailInfo << "debug-switch ";
1171  .setNamedValue(args_[argi], 1, true, true); // dryrun
1172  }
1173  else if (strcmp(optName, "info-switch") == 0)
1174  {
1175  // The '-info-switch' option:
1176  // dryrun reporting only (already set above)
1177  DetailInfo << "info-switch ";
1179  .setNamedValue(args_[argi], 1, true, true); // dryrun
1180  }
1181  else if (strcmp(optName, "opt-switch") == 0)
1182  {
1183  // The '-opt-switch' option:
1184  // dryrun reporting only (already set above)
1185  DetailInfo << "opt-switch ";
1187  .setNamedValue(args_[argi], 1, true, true); // dryrun
1188  }
1189  else
1190  {
1191  // Regular option (with a parameter):
1192  // Duplicates handled by using the last -option specified
1193  options_.set(optName, args_[argi]);
1194  }
1195  }
1196  else
1197  {
1198  // All other options (including unknown ones) are simply
1199  // registered as existing.
1200 
1201  options_.insert(optName, "");
1202 
1203  // // Special increment handling for some known flags
1204  // if (wantArg.good())
1205  // {
1206  // ...
1207  // }
1208  }
1209  }
1210  else
1211  {
1212  if (nArgs != argi)
1213  {
1214  args_[nArgs] = args_[argi];
1215  }
1216  ++nArgs;
1217  }
1218  }
1219 
1220  args_.resize(nArgs);
1221 
1222  parse(checkArgs, checkOpts, initialise);
1223 }
1224 
1225 
1227 (
1228  const argList& args,
1229  const HashTable<string>& options,
1230  bool checkArgs,
1231  bool checkOpts,
1232  bool initialise
1233 )
1234 :
1235  runControl_(args.runControl_),
1236  args_(args.args_),
1237  options_(options),
1238  libs_(),
1239  executable_(args.executable_),
1240  rootPath_(args.rootPath_),
1241  globalCase_(args.globalCase_),
1242  case_(args.case_),
1243  commandLine_(args.commandLine_)
1244 {
1245  parse(checkArgs, checkOpts, initialise);
1246 }
1247 
1248 
1250 (
1251  bool checkArgs,
1252  bool checkOpts,
1253  bool initialise
1254 )
1255 {
1256  // Help/documentation options:
1257  // -doc Display documentation in browser
1258  // -doc-source Display source code in browser
1259  // -help Display short help and exit
1260  // -help-compat Display compatibility options
1261  // -help-full Display full help and exit
1262  {
1263  bool quickExit = false;
1264 
1265  // Display either application or source documentation, not both
1266  if (options_.contains("doc"))
1267  {
1268  displayDoc(false);
1269  quickExit = true;
1270  }
1271  else if (options_.contains("doc-source"))
1272  {
1273  displayDoc(true);
1274  quickExit = true;
1275  }
1276 
1277  // Display either short or full help, not both
1278  if (options_.contains("help-full"))
1279  {
1280  printUsage(true);
1281  quickExit = true;
1282  }
1283  else if (options_.contains("help-notes"))
1284  {
1285  printNotes();
1286  Info<< nl;
1287  quickExit = true;
1288  }
1289  else if (options_.contains("help"))
1290  {
1291  printUsage(false);
1292  quickExit = true;
1293  }
1294  else if (options_.contains("help-man"))
1295  {
1296  printMan();
1297  quickExit = true;
1298  }
1299 
1300  // Allow independent display of compatibility information
1301  if (options_.contains("help-compat"))
1302  {
1303  printCompat();
1304  quickExit = true;
1305  }
1306 
1307  if (quickExit)
1308  {
1309  std::exit(0);
1310  }
1311  }
1312 
1313  // Print the collected error messages and exit if check fails
1314  if (!check(checkArgs, checkOpts))
1315  {
1317  FatalError.write(Info, false);
1318 
1319  UPstream::exit(1); // works for serial and parallel
1320  }
1321 
1322  if (initialise)
1323  {
1324  const string dateString = clock::date();
1325  const string timeString = clock::clockTime();
1326 
1327  // Print the banner once only for parallel runs
1328  if (UPstream::master() && bannerEnabled())
1329  {
1331  << "Build : ";
1332 
1333  if (foamVersion::build.size())
1334  {
1335  Info<< foamVersion::build.c_str() << ' ';
1336  }
1337 
1338  Info<< "OPENFOAM=" << foamVersion::api;
1339 
1340  if (foamVersion::patched())
1341  {
1342  // Patch-level, when defined
1343  Info<< " patch=" << foamVersion::patch.c_str();
1344  }
1345 
1346  Info<< " version=" << foamVersion::version.c_str();
1347 
1348  Info<< nl
1349  << "Arch : " << foamVersion::buildArch << nl
1350  << "Exec : " << commandLine_.c_str() << nl
1351  << "Date : " << dateString.c_str() << nl
1352  << "Time : " << timeString.c_str() << nl
1353  << "Host : " << Foam::hostName().c_str() << nl
1354  << "PID : " << pid() << nl;
1355  }
1356 
1357  jobInfo.add("startDate", dateString);
1358  jobInfo.add("startTime", timeString);
1359  jobInfo.add("userName", userName());
1360 
1361  jobInfo.add("foamApi", foamVersion::api);
1362  jobInfo.add("foamVersion", word(foamVersion::version));
1363 
1364  // Add build information - only use the first word
1365  {
1366  std::string build(foamVersion::build);
1367  const auto space = build.find(' ');
1368  if (space != std::string::npos)
1369  {
1370  build.resize(space);
1371  }
1372  jobInfo.add("foamBuild", build);
1373  }
1374 
1375  jobInfo.add("code", executable_);
1376  jobInfo.add("argList", commandLine_);
1377  jobInfo.add("currentDir", cwd());
1378  jobInfo.add("PPID", ppid());
1379  jobInfo.add("PGID", pgid());
1380 
1381  // Load additional libraries (verbosity according to banner setting)
1382  libs().open(bannerEnabled());
1383  }
1384 
1385 
1386  // Set fileHandler. In increasing order of priority:
1387  // 1. default = uncollated
1388  // 2. env variable "FOAM_FILEHANDLER"
1389  // 3. etc/controlDict optimisationSwitches 'fileHandler'
1390  // 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)
1391  // 5. '-fileHandler' commmand-line option
1392 
1393  {
1394  word fileHandlerName
1395  (
1396  options_.lookup("fileHandler", Foam::getEnv("FOAM_FILEHANDLER"))
1397  );
1398 
1399  if (fileHandlerName.empty())
1400  {
1401  fileHandlerName = fileOperation::defaultFileHandler;
1402  }
1403 
1405  (
1406  fileOperation::New(fileHandlerName, bannerEnabled())
1407  );
1408  }
1409 
1410 
1411  stringList hostMachine;
1412  stringList hostProcs;
1413  const int writeHostsSwitch = Foam::debug::infoSwitch("writeHosts", 1);
1414  const int writeRootsSwitch = Foam::debug::infoSwitch("writeRoots", 1);
1415 
1416  // Collect machine/pid, and check that the build is identical
1417  if (runControl_.parRun())
1418  {
1419  if (UPstream::master())
1420  {
1421  hostMachine.resize(UPstream::nProcs()-1);
1422  hostProcs.resize(UPstream::nProcs()-1);
1423  string procBuild;
1424  label procPid;
1425  int proci = 0;
1426  for (const int subproci : UPstream::subProcs())
1427  {
1428  IPstream fromSubproc(UPstream::commsTypes::scheduled, subproci);
1429 
1430  fromSubproc >> procBuild >> hostMachine[proci] >> procPid;
1431 
1432  hostProcs[proci] = hostMachine[proci] + "." + name(procPid);
1433  ++proci;
1434 
1435  // Verify that all processors are running the same build
1436  if (procBuild != foamVersion::build)
1437  {
1438  FatalErrorIn(executable())
1439  << "Running build version " << foamVersion::build
1440  << " but proc " << subproci << " is running "
1441  << procBuild << nl
1442  << exit(FatalError);
1443  }
1444  }
1445  }
1446  else
1447  {
1448  OPstream toMaster
1449  (
1452  );
1453  toMaster << foamVersion::build << Foam::hostName() << Foam::pid();
1454  }
1455  }
1456 
1457 
1458  // Case is a single processor run unless it is running parallel
1459  int nProcs = 1;
1460 
1461  // Roots if running distributed. Only sized on the master
1462  fileNameList roots;
1463 
1464  enum distributedCodes
1465  {
1466  NON_DISTRIBUTED = 0,
1467  DISTRIBUTED = 1,
1468  DISTRIBUTED_SINGLE_ROOT = 2,
1469  DISTRIBUTED_MULTIPLE_ROOTS = 3
1470  };
1471 
1472  // Track which type of distributed roots etc are being used
1473  label distributedType
1474  (
1475  runControl_.distributed()
1476  ? distributedCodes::DISTRIBUTED
1477  : distributedCodes::NON_DISTRIBUTED
1478  );
1479 
1480  // Some cases where knowing the writeFormat can be useful...
1481  // label writeFormat(-1);
1482 
1483 
1484  // If this actually is a parallel run
1485  if (runControl_.parRun())
1486  {
1487  // For the master
1488  if (UPstream::master())
1489  {
1490  // Establish rootPath_/globalCase_/case_ for master
1491  setCasePaths();
1492 
1493  // The system/decomposeParDict (or equivalent)
1494  fileName source;
1495 
1496  if (this->readIfPresent("decomposeParDict", source))
1497  {
1498  bool adjustOpt = false;
1499 
1500  if (Foam::isDir(source))
1501  {
1502  source /= "decomposeParDict";
1503  adjustOpt = true;
1504  }
1505 
1506  // Case-relative if not absolute and not "./" etc
1507  if (!source.isAbsolute() && !source.starts_with('.'))
1508  {
1509  source = rootPath_/globalCase_/source;
1510  adjustOpt = true;
1511  }
1512 
1513  // Could also check for absolute path, but shouldn't be needed
1514  if (adjustOpt)
1515  {
1516  source.clean(); // Remove unneeded ".."
1517  options_.set("decomposeParDict", source);
1518  }
1519  }
1520 
1521  // If running distributed (different roots for different procs)
1522  label dictNProcs = -1;
1523  if (this->readListIfPresent("roots", roots))
1524  {
1525  source = "-roots";
1526  runControl_.distributed(true);
1527  distributedType = distributedCodes::DISTRIBUTED;
1528 
1529  if (roots.empty())
1530  {
1532  << "The -roots option must contain values"
1533  << exit(FatalError);
1534  }
1535  if (roots.size() > 1)
1536  {
1537  dictNProcs = roots.size()+1;
1538  }
1539  }
1540  else if (options_.contains("hostRoots"))
1541  {
1542  source = "-hostRoots";
1543  runControl_.distributed(true);
1544  distributedType = distributedCodes::DISTRIBUTED;
1545 
1546  ITstream is(this->lookup("hostRoots"));
1547 
1548  List<Tuple2<wordRe, fileName>> hostRoots(is);
1549  checkITstream(is, "hostRoots");
1550 
1551  if (hostRoots.empty())
1552  {
1554  << "The -hostRoots option must contain values"
1555  << exit(FatalError);
1556  }
1557 
1558  // Match machine names to roots
1559  roots.resize(UPstream::nProcs()-1, fileName::null);
1560  for (const auto& hostRoot : hostRoots)
1561  {
1562  labelList matched
1563  (
1564  wordRes::matching(hostRoot.first(), hostMachine)
1565  );
1566  for (const label matchi : matched)
1567  {
1568  if (!roots[matchi].empty())
1569  {
1571  << "Multiple matching roots for "
1572  << hostMachine[matchi] << " in "
1573  << hostRoots << nl
1574  << exit(FatalError);
1575  }
1576 
1577  roots[matchi] = hostRoot.second();
1578  }
1579  }
1580 
1581  // Check
1582  forAll(roots, hosti)
1583  {
1584  if (roots[hosti].empty())
1585  {
1587  << "No matching roots for "
1588  << hostMachine[hosti] << " in "
1589  << hostRoots << nl
1590  << exit(FatalError);
1591  }
1592  }
1593 
1594  if (roots.size() > 1)
1595  {
1596  dictNProcs = roots.size()+1;
1597  }
1598  }
1599  else if (checkProcessorDirectories_ && UPstream::nProcs() > 1)
1600  {
1601  // Check values from decomposeParDict
1602 
1603  const bool useDefault = source.empty();
1604  if (useDefault)
1605  {
1606  source = rootPath_/globalCase_/"system"/"decomposeParDict";
1607  }
1608 
1609  // Disable any parallel comms happening inside the fileHandler
1610  // since we are on master. This can happen e.g. inside
1611  // the masterUncollated/collated handler. Note that we
1612  // also have to protect the actual dictionary parsing since
1613  // it might trigger file access (e.g. #include, #codeStream)
1614  const bool oldParRun = UPstream::parRun(false);
1615  // Note: non-parallel running might update
1616  // fileOperation::nProcs() so store & restore below
1617  const label nOldProcs = fileHandler().nProcs();
1618 
1619  autoPtr<ISstream> dictStream
1620  (
1621  fileHandler().NewIFstream(source)
1622  );
1623 
1624  if (dictStream && dictStream->good())
1625  {
1626  // Get numberOfSubdomains if it exists.
1627  // - mandatory when running with distributed roots
1628 
1629  IOobjectOption::readOption nDomainsReadOpt
1631 
1632  dictionary decompDict(*dictStream);
1633 
1634  if (decompDict.getOrDefault("distributed", false))
1635  {
1636  nDomainsReadOpt = IOobjectOption::MUST_READ;
1637  runControl_.distributed(true);
1638  distributedType = distributedCodes::DISTRIBUTED;
1639 
1640  decompDict.readEntry("roots", roots);
1641 
1642  if (roots.empty())
1643  {
1644  DetailInfo
1645  << "WARNING: running distributed"
1646  << " but did not specify roots!" << nl;
1647  }
1648  }
1649 
1650  decompDict.readEntry
1651  (
1652  "numberOfSubdomains",
1653  dictNProcs,
1655  nDomainsReadOpt
1656  );
1657  }
1658  else
1659  {
1660  if (useDefault)
1661  {
1662  // Optional if using default location
1663  DetailInfo
1664  << "WARNING: running without decomposeParDict "
1665  << this->relativePath(source) << nl;
1666  }
1667  else
1668  {
1669  // Mandatory if specified as -decomposeParDict
1670  FatalError
1671  << "Cannot read decomposeParDict: "
1672  << this->relativePath(source) << nl
1673  << exit(FatalError);
1674  }
1675  }
1676 
1677  UPstream::parRun(oldParRun); // Restore parallel state
1678  const_cast<fileOperation&>(fileHandler()).nProcs(nOldProcs);
1679 
1680  if (UPstream::nProcs() == 1)
1681  {
1682  Warning
1683  << "Running parallel on single processor. This only"
1684  << " makes sense for multi-world simulation" << endl;
1685  dictNProcs = 1;
1686  }
1687  }
1688 
1689 
1690  // Distributed roots
1691  if (!roots.empty())
1692  {
1693  for (fileName& dir : roots)
1694  {
1695  dir.expand();
1696  }
1697 
1698  // Identical root specified everywhere?
1699  // - use optimized single-root variant
1700  if (roots.size() > 1 && roots.uniform())
1701  {
1702  roots.resize(1);
1703  }
1704 
1705  if (roots.size() == 1)
1706  {
1707  // Single root specified, use it for all processes
1708  distributedType =
1709  distributedCodes::DISTRIBUTED_SINGLE_ROOT;
1710 
1711  // Adjust dictNProcs for command-line '-roots' option
1712  if (dictNProcs <= 0)
1713  {
1714  dictNProcs = UPstream::nProcs();
1715  }
1716  }
1717  else if (roots.size() > 1)
1718  {
1719  distributedType =
1720  distributedCodes::DISTRIBUTED_MULTIPLE_ROOTS;
1721 
1722  if (roots.size() != UPstream::nProcs()-1)
1723  {
1724  FatalError
1725  << "Number of roots " << roots.size()
1726  << " != number of sub-ranks "
1727  << UPstream::nProcs()-1
1728  << exit(FatalError);
1729  }
1730  }
1731  }
1732 
1733 
1734  //
1735  // Check number of processors.
1736  //
1737 
1738  // nProcs => number of actual procs
1739  // dictNProcs => number of procs specified in decompositionDict
1740  // nProcDirs => number of processor directories
1741  // (n/a when running distributed)
1742  //
1743  // - normal running : nProcs = dictNProcs = nProcDirs
1744  // - decomposition to more processors : nProcs = dictNProcs
1745  // - decomposition to fewer processors : nProcs = nProcDirs
1746  if
1747  (
1748  checkProcessorDirectories_
1749  && UPstream::nProcs() > 1
1750  )
1751  {
1752  if (dictNProcs > UPstream::nProcs())
1753  {
1754  FatalError
1755  << this->relativePath(source)
1756  << " specifies " << dictNProcs
1757  << " processors but job was started with "
1758  << UPstream::nProcs() << " ranks."
1759  << exit(FatalError);
1760  }
1761 
1762  // Possibly going to fewer processors.
1763  // Check if all procDirs are there.
1764  // NOTE: Only works when not using distributed roots!
1765  if
1766  (
1767  // Can only rely on directory scanning *without* distributed roots!
1768  roots.empty()
1769  && dictNProcs >= 1
1770  && dictNProcs < UPstream::nProcs()
1771  )
1772  {
1773  label nProcDirs = 0;
1774  {
1775  const bool oldParRun = UPstream::parRun(false);
1776  // Don't cache processor directories (probably not
1777  // needed since master-only
1778  const int oldCacheLevel(fileOperation::cacheLevel(0));
1779  // Accept any processorsXXX
1780  const int oldFilter(fileOperation::nProcsFilter(0));
1781 
1782  nProcDirs = fileHandler().nProcs
1783  (
1784  rootPath_/globalCase_,
1785  "",
1786  dictNProcs // expected nProcs
1787  );
1788 
1789  fileOperation::nProcsFilter(oldFilter);
1790  fileOperation::cacheLevel(oldCacheLevel);
1791  UPstream::parRun(oldParRun);
1792  }
1793 
1794  if (nProcDirs < UPstream::nProcs())
1795  {
1796  FatalError
1797  << "Number of processor directories = " << nProcDirs
1798  << " is not equal to the number of ranks = "
1799  << UPstream::nProcs()
1800  << exit(FatalError);
1801  }
1802  }
1803  }
1804 
1805 
1806  // Broadcast the master's argument list (unaltered)
1807  {
1808  OPBstream toProcs(UPstream::worldComm);
1809 
1810  toProcs
1811  << args_ << options_
1812  << distributedType
1813  << label(runControl_.dryRun())
1814  << label(runControl_.verbose());
1815  }
1816  }
1817  else
1818  {
1819  // Receive the broadcasted master's argument list
1820  label numDryRun, numVerbose;
1821 
1822  IPBstream fromMaster(UPstream::worldComm);
1823 
1824  fromMaster
1825  >> args_ >> options_
1826  >> distributedType
1827  >> numDryRun >> numVerbose;
1828 
1829  runControl_.distributed(distributedType);
1830  runControl_.dryRun(numDryRun);
1831  runControl_.verbose(numVerbose);
1832  }
1833 
1834 
1835  // Final handling of distributed roots (if any)
1836  if
1837  (
1838  distributedType == distributedCodes::DISTRIBUTED_SINGLE_ROOT
1839  )
1840  {
1841  // The same root for all sub-ranks
1842  // - use broadcast to transmit value
1843 
1844  fileName newCasePath;
1845 
1846  if (UPstream::master())
1847  {
1848  newCasePath = roots[0]/globalCase_;
1849  OPBstream::send(newCasePath); // worldComm
1850  }
1851  else
1852  {
1853  IPBstream::recv(newCasePath); // worldComm
1854  options_.set("case", newCasePath);
1855  }
1856  }
1857  else if
1858  (
1859  distributedType == distributedCodes::DISTRIBUTED_MULTIPLE_ROOTS
1860  )
1861  {
1862  // Different roots for each sub-rank
1863  // - use point-to-point communication to transmit values
1864 
1865  fileName newCasePath;
1866 
1867  if (UPstream::master())
1868  {
1869  for (const int subproci : UPstream::subProcs())
1870  {
1871  newCasePath = roots[subproci-1]/globalCase_;
1872  OPstream::send(newCasePath, subproci); // worldComm
1873  }
1874  }
1875  else
1876  {
1877  IPstream::recv(newCasePath, UPstream::masterNo()); // worldComm
1878  options_.set("case", newCasePath);
1879  }
1880  }
1881 
1882 
1883  // Establish rootPath_/globalCase_/case_ for sub-process
1884  if (!UPstream::master())
1885  {
1886  setCasePaths();
1887  }
1888 
1889 
1890  nProcs = UPstream::nProcs();
1891  if (UPstream::nProcs() > 1)
1892  {
1893  case_ =
1894  (
1895  globalCase_
1896  / ("processor" + Foam::name(UPstream::myProcNo()))
1897  );
1898  }
1899  else
1900  {
1901  case_ = globalCase_;
1902  }
1903  }
1904  else
1905  {
1906  // Establish rootPath_/globalCase_/case_
1907  setCasePaths();
1908  case_ = globalCase_; // Redundant, but extra safety?
1909  }
1910 
1911 
1912  // If needed, adjust fileHandler for distributed roots
1913  if (runControl_.distributed() && fileOperation::fileHandlerPtr_)
1914  {
1915  fileOperation::fileHandlerPtr_->distributed(true);
1916 
1917  const labelList& ranks = fileHandler().ioRanks();
1918 
1919  if (runControl_.parRun() && ranks.size())
1920  {
1921  // Detect processor directories both on local proc and on
1922  // (world) master proc. If the local proc doesn't have them
1923  // but the master has it will attempt to copy them.
1924 
1925  // Expected local directory name
1926  const fileName procDir
1927  (
1928  rootPath_
1929  / globalCase_
1930  / ("processor" + Foam::name(UPstream::myProcNo()))
1931  );
1932 
1933  // Try and find my local directory using the fileHandler. This
1934  // will check the local disk on the IO rank
1935  // (since running distributed)
1936  fileNameList pathDirs(UPstream::nProcs());
1937  auto& pathDir = pathDirs[UPstream::myProcNo()];
1938  pathDir = fileHandler().filePath(procDir, false);
1939 
1940  if (returnReduceOr(pathDir.empty()))
1941  {
1942  // There is at least one processor that cannot find
1943  // the processor directory. Look for it on the master.
1944  // E.g. decomposed into 4 processors, two roots:
1945  // processors4_0-1/
1946  // processors4_2-3/
1947  // So:
1948  // - processor0 reads the same disk as processor0
1949  // - processor2 needs the whole directory sent over
1950  // - processor3 reads the same disk as processor2
1951  if (UPstream::master() && bannerEnabled())
1952  {
1953  Info<< "I/O :"
1954  << " distributed - copying missing directories"
1955  << nl;
1956  }
1957 
1958  // Collect all wanted directories (or empty). Note: could
1959  // just collect missing ones ...
1960 
1961  Pstream::gatherList(pathDirs);
1962  fileName masterRootPath(rootPath_);
1963  Pstream::broadcast(masterRootPath);
1964 
1965  List<fileNameList> rankToDirs(UPstream::nProcs());
1966  if (UPstream::master())
1967  {
1968  const bool oldParRun = UPstream::parRun(false);
1969  // Note: non-parallel running might update
1970  // fileOperation::nProcs() so store & restore below
1971  const label nOldProcs = fileHandler().nProcs();
1972 
1973  label rank = 0;
1974  for (label proci = 1; proci < pathDirs.size(); ++proci)
1975  {
1976  if (ranks.contains(proci))
1977  {
1978  rank = proci;
1979  }
1980 
1981  if (pathDirs[proci].empty())
1982  {
1983  // Synthesise corresponding name on the master
1984  // processor
1985  const fileName procDir
1986  (
1987  rootPath_
1988  / globalCase_
1989  / ("processor" + Foam::name(proci))
1990  );
1991  const fileName foundDir
1992  (
1993  fileHandler().filePath(procDir, false)
1994  );
1995 
1996  if
1997  (
1998  !foundDir.empty()
1999  && !rankToDirs[rank].contains(foundDir)
2000  )
2001  {
2002  rankToDirs[rank].push_back(foundDir);
2003  }
2004  }
2005  }
2006 
2007  UPstream::parRun(oldParRun);
2008  const_cast<fileOperation&>(fileHandler()).nProcs(nOldProcs);
2009  }
2010  Pstream::broadcast(rankToDirs);
2011 
2012  // Copy missing directories on all the IOranks.
2013  // Note: instead of passing 'writeOnProc' flag we could create
2014  // communicator just between master and IOrank, but that is
2015  // also expensive.
2016 
2017  forAll(rankToDirs, proci)
2018  {
2019  // Am I the reponsible IOrank for this processor
2020  const bool amIO = (UPstream::myProcNo() == proci);
2021 
2022  // Construct equivalent directory on proci
2023  for (const auto& srcDir : rankToDirs[proci])
2024  {
2025  const fileName tgtDir
2026  (
2027  rootPath_
2028  / srcDir.relative(masterRootPath)
2029  );
2030 
2031  if (amIO)
2032  {
2033  // I am the IO rank
2034  Pout<< "On rank " << proci << nl
2035  << " copying : " << srcDir << nl
2036  << " to : " << tgtDir << endl;
2037  }
2038 
2039  fileHandler().broadcastCopy
2040  (
2042  amIO,
2043  tgtDir,
2044  tgtDir
2045  );
2046  }
2047  }
2048  }
2049  }
2050  }
2051 
2052 
2053  // Keep/discard sub-process host/root information for reporting:
2054  if (UPstream::master() && runControl_.parRun())
2055  {
2056  if (!writeHostsSwitch)
2057  {
2058  // Clear here to ensures it doesn't show in the jobInfo
2059  hostProcs.clear();
2060  }
2061  if (!writeRootsSwitch)
2062  {
2063  roots.clear();
2064  }
2065  }
2066 
2067  if (UPstream::master() && bannerEnabled())
2068  {
2069  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
2070  << "nProcs : " << nProcs << nl;
2071 
2072  if (runControl_.parRun())
2073  {
2074  if (hostProcs.size())
2075  {
2076  if (writeHostsSwitch == 1)
2077  {
2078  // Compact output (see etc/controlDict)
2079  printHostsSubscription(hostProcs);
2080  }
2081  else if (writeHostsSwitch)
2082  {
2083  // Full output of "host.pid"
2084  Info<< "Hosts :\n(" << nl;
2085 
2086  // Include master in the list
2087  Info<< " " << Foam::hostName().c_str() << '.'
2088  << Foam::pid() << nl;
2089 
2090  // Sub-processes
2091  for (const auto& str : hostProcs)
2092  {
2093  Info<< " " << str.c_str() << nl;
2094  }
2095  Info<< ')' << nl;
2096  }
2097  }
2098  if (roots.size())
2099  {
2100  bool hasPrinted = false;
2101  if (writeRootsSwitch == 1)
2102  {
2103  // Compact output
2104  hasPrinted = printRootsSubscription(hostProcs, roots);
2105  }
2106  if (writeRootsSwitch && !hasPrinted)
2107  {
2108  // Full output
2109  Info<< "Roots : " << roots << nl;
2110  }
2111  }
2112 
2113  Info<< "Pstream initialized with:" << nl;
2114  {
2115  Info<< " node communication : ";
2117  Info<< nl;
2118  }
2119  {
2120  Info<< " topology controls : ";
2122  Info<< nl;
2123  }
2124 
2126  {
2127  Info<< " floatTransfer : enabled" << nl;
2128  }
2130  {
2131  Info<< " maxCommsSize : "
2132  << UPstream::maxCommsSize << nl;
2133  }
2134  if (UPstream::nProcsSimpleSum > 2)
2135  {
2136  Info<< " nProcsSimpleSum : "
2138  }
2139  {
2140  const auto& commsType =
2142 
2143  Info<< " consensus exchange : "
2145  << " (tuning: " << UPstream::tuning_NBX_ << ')' << nl
2146  << " exchange algorithm : "
2148  << " commsType : " << commsType << nl
2149  << " polling iterations : "
2151  }
2152 
2153  if (UPstream::allWorlds().size() > 1)
2154  {
2155  Info<< " worlds : "
2157  << " world : " << UPstream::myWorld()
2158  << nl;
2159  }
2160  }
2161  }
2162 
2163  if (initialise)
2164  {
2165  jobInfo.add("root", rootPath_);
2166  jobInfo.add("case", globalCase_);
2167  jobInfo.add("nProcs", nProcs);
2168  if (hostProcs.size())
2169  {
2170  jobInfo.add("hosts", hostProcs);
2171  }
2172  if (roots.size())
2173  {
2174  jobInfo.add("roots", roots);
2175  }
2176  jobInfo.write();
2177 
2178  // Switch on signal trapping. We have to wait until after Pstream::init
2179  // since this sets up its own ones.
2180  sigFpe::set(bannerEnabled());
2181  sigInt::set(bannerEnabled());
2182  sigQuit::set(bannerEnabled());
2183  sigSegv::set(bannerEnabled());
2184 
2185  if (UPstream::master() && bannerEnabled())
2186  {
2187  Info<< "fileModificationChecking : "
2188  << "Monitoring run-time modified files using "
2190  [
2192  ];
2193  if
2194  (
2197  )
2198  {
2200  {
2201  Info<< " (fileModificationSkew "
2203  << ")";
2204  }
2206  {
2207  Info<< " (fileModificationSkew "
2209  << ", maxFileModificationPolls "
2211  << ")";
2212  }
2213  else
2214  {
2216  << "Invalid setting for maxFileModificationPolls "
2218  << exit(FatalError);
2219  }
2220  }
2221  Info<< nl;
2222 
2223  Info<< "allowSystemOperations : ";
2225  {
2226  Info<< "Allowing";
2227  }
2228  else
2229  {
2230  Info<< "Disallowing";
2231  }
2232  Info<< " user-supplied system call operations" << nl
2233  << nl;
2235 
2236  // Ugly handling of localBoundaryConsistency switches
2238  (
2240  );
2241  }
2242  }
2243 }
2244 
2245 
2246 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
2247 
2249 {
2250  jobInfo.stop(); // Normal job termination
2251 
2252  // Delete file handler to flush any remaining IO
2253  (void) fileOperation::fileHandler(nullptr);
2254 }
2255 
2256 
2257 // * * * * * * * * * * * * * * * Capabilities * * * * * * * * * * * * * * * //
2258 
2260 {
2261  if (validOptions.contains("withFunctionObjects"))
2262  {
2263  // '-withFunctionObjects' is available and explicitly enabled
2264  return options_.contains("withFunctionObjects");
2265  }
2266  else if (validOptions.contains("noFunctionObjects"))
2267  {
2268  // '-noFunctionObjects' is available and not explicitly disabled
2269  return !options_.contains("noFunctionObjects");
2270  }
2271 
2272  // Disallow functions if there is no way to enable/disable them
2273  return false;
2274 }
2275 
2276 
2277 bool Foam::argList::allowLibs() const
2279  return !options_.contains("no-libs");
2280 }
2281 
2282 
2283 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2284 
2285 Foam::label Foam::argList::count(const UList<word>& optionNames) const
2286 {
2287  label num = 0;
2288  for (const word& optName : optionNames)
2289  {
2290  if (options_.contains(optName))
2291  {
2292  ++num;
2293  }
2294  }
2295  return num;
2296 }
2297 
2298 
2299 Foam::label Foam::argList::count(std::initializer_list<word> optionNames) const
2300 {
2301  label num = 0;
2302  for (const word& optName : optionNames)
2303  {
2304  if (options_.contains(optName))
2305  {
2306  ++num;
2307  }
2308  }
2309  return num;
2310 }
2311 
2312 
2313 bool Foam::argList::setOption(const word& optName, const string& param)
2314 {
2315  // Some options are always protected
2316  if
2317  (
2318  optName == "case"
2319  || optName == "parallel"
2320  || optName == "roots"
2321  )
2322  {
2324  <<"Option: '" << optName << "' is protected" << nl
2325  << exit(FatalError);
2326  return false;
2327  }
2328 
2329  const auto optIter = options_.cfind(optName);
2330 
2331  if (!optIter.good() || (optIter.val() != param))
2332  {
2333  options_.set(optName, param);
2334  return true;
2335  }
2336 
2337  return false;
2338 }
2339 
2340 
2341 bool Foam::argList::unsetOption(const word& optName)
2342 {
2343  // Some options are always protected
2344  if
2345  (
2346  optName == "case"
2347  || optName == "parallel"
2348  || optName == "roots"
2349  )
2350  {
2352  <<"Option: '" << optName << "' is protected" << nl
2353  << exit(FatalError);
2354  return false;
2355  }
2356 
2357  // Remove the option, return true if state changed
2358  return options_.erase(optName);
2359 }
2360 
2361 
2362 void Foam::argList::displayDoc(bool source) const
2363 {
2364  const dictionary& docDict = debug::controlDict().subDict("Documentation");
2365  fileNameList docDirs(docDict.get<fileNameList>("doxyDocDirs"));
2366  fileName docExt(docDict.get<fileName>("doxySourceFileExt"));
2367 
2368  // For source code: change xxx_8C.html to xxx_8C_source.html
2369  if (source)
2370  {
2371  docExt.replace(".", "_source.");
2372  }
2373 
2374  fileName url;
2375 
2376  for (const fileName& dir : docDirs)
2377  {
2378  // The http protocols are last in the list
2379  if (dir.starts_with("http:") || dir.starts_with("https:"))
2380  {
2381  url = dir/executable_ + docExt;
2382  break;
2383  }
2384 
2385  fileName docFile = stringOps::expand(dir/executable_ + docExt);
2386 
2387  if
2388  (
2389  docFile.starts_with("file://")
2390  ? isFile(docFile.substr(7)) // check part after "file://"
2391  : isFile(docFile)
2392  )
2393  {
2394  url = std::move(docFile);
2395  break;
2396  }
2397  }
2398 
2399  if (url.empty())
2400  {
2401  Info<< nl
2402  << "No documentation found for " << executable_
2403  << ", but you can use -help to display the usage\n" << endl;
2404 
2405  return;
2406  }
2407 
2408  string docBrowser = getEnv("FOAM_DOC_BROWSER");
2409  if (docBrowser.empty())
2410  {
2411  docDict.readEntry("docBrowser", docBrowser);
2412  }
2413 
2414  // Can use FOAM_DOC_BROWSER='application file://%f' if required
2415  if (docBrowser.contains("%f"))
2416  {
2417  docBrowser.replace("%f", url);
2418  }
2419  else
2420  {
2421  docBrowser += " " + url;
2422  }
2423 
2424  // Split on whitespace to use safer version of Foam::system()
2425 
2426  CStringList command(stringOps::splitSpace(docBrowser));
2427 
2428  Info
2429  << "OpenFOAM " << foamVersion::api << " documentation:" << nl
2430  << " " << command << nl << endl;
2431 
2432  Foam::system(command, true);
2433 }
2434 
2435 
2436 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
2437 {
2438  bool ok = true;
2439 
2440  if (UPstream::master())
2441  {
2442  const label nargs = args_.size()-1;
2443  if (checkArgs && nargs != validArgs.size())
2444  {
2445  FatalError
2446  << "Expected " << validArgs.size()
2447  << " arguments but found " << nargs << endl;
2448  ok = false;
2449  }
2450 
2451  if (checkOpts)
2452  {
2453  forAllConstIters(options_, iter)
2454  {
2455  const word& optName = iter.key();
2456  if
2457  (
2458  !validOptions.contains(optName)
2459  && !validParOptions.contains(optName)
2460  )
2461  {
2462  FatalError
2463  << "Invalid option: -" << optName << endl;
2464  ok = false;
2465  }
2466  }
2467  }
2468 
2469  if (!ok)
2470  {
2471  FatalError
2472  << nl
2473  << "See '" << executable_ << " -help' for usage" << nl
2474  << " or '" << executable_
2475  << " -help-full' for extended usage" << nl
2476  << nl;
2477  }
2478  }
2479 
2480  return ok;
2481 }
2482 
2483 
2484 bool Foam::argList::checkRootCase() const
2485 {
2486  if (!fileHandler().isDir(rootPath()))
2487  {
2488  FatalError
2489  << executable_
2490  << ": cannot open root directory " << rootPath()
2491  << endl;
2492 
2493  return false;
2494  }
2495 
2496  const fileName pathDir(fileHandler().filePath(path(), false));
2497 
2498  if (checkProcessorDirectories_ && pathDir.empty() && UPstream::master())
2499  {
2500  // Allow non-existent processor directories on sub-processes,
2501  // to be created later (e.g. redistributePar)
2502  FatalError
2503  << executable_
2504  << ": cannot open case directory " << path()
2505  << endl;
2506 
2507  return false;
2508  }
2509 
2510  return true;
2511 }
2512 
2513 
2514 // ************************************************************************* //
static void noJobInfo()
Suppress JobInfo, overriding controlDict setting.
Definition: argList.C:581
static bool floatTransfer
Should compact transfer be used in which floats replace doubles reducing the bandwidth requirement at...
Definition: UPstream.H:942
static const word & myWorld()
My world.
Definition: UPstream.H:1707
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:2477
void printBuildInfo(std::ostream &os, const bool full=true)
Print information about version, build, arch to output stream.
static void recv(Type &value, const int communicator=UPstream::worldComm)
Receive (from broadcast, root == UPstream::masterNo()) and deserialize a value. Uses operator>> for d...
Definition: IPstream.H:139
static refPtr< fileOperation > fileHandlerPtr_
The currently active file handler. Avoid accessing directly.
static void set(bool verbose=false)
Activate SIGFPE handler when FOAM_SIGFPE is enabled. Activate fill memory with signaling_NaN when FOA...
static void noFunctionObjects(bool addWithOption=false)
Remove &#39;-noFunctionObjects&#39; option and ignore any occurrences.
Definition: argList.C:561
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:476
A class for handling file names.
Definition: fileName.H:72
static const Enum< commsTypes > commsTypeNames
Enumerated names for the communication types.
Definition: UPstream.H:89
static void setAdvanced(const word &optName, bool advanced=true)
Set an existing option as being &#39;advanced&#39; or normal.
Definition: argList.C:418
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:493
static int nProcsFilter() noexcept
Return collated &#39;processorsDDD&#39; filtering.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
Foam::SubStrings splitSpace(const std::string &str, std::string::size_type pos=0)
Split string into sub-strings at whitespace (TAB, NL, VT, FF, CR, SPC)
bool unsetOption(const word &optName)
Unset option directly (use with caution)
Definition: argList.C:2334
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:356
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:600
static void printNodeCommsControl(Ostream &os)
Report the node-communication settings.
Definition: UPstream.C:56
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:322
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
static int maxCommsSize
Optional maximum message size (bytes)
Definition: UPstream.H:968
static const fileName null
An empty fileName.
Definition: fileName.H:111
static int nProcsSimpleSum
Number of processors to change from linear to tree communication.
Definition: UPstream.H:947
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:529
static Ostream & writeDivider(Ostream &os)
Write the standard file section divider.
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
void setNamedValue(const std::string_view name, int val, bool verbose=false, bool dryrun=false)
Set named value, but also handle embedded &#39;name=value&#39; syntax.
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:212
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:388
static void noParallel()
Remove the parallel options.
Definition: argList.C:598
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:432
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:262
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
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.
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:625
static bool postProcess(int argc, char *argv[])
True if the post-processing option is found in the argv list.
Definition: argList.C:624
Operations on lists of strings.
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
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:341
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1611
static HashTable< string, label, Hash< label > > argUsage
Short description for program arguments.
Definition: argList.H:279
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:987
void runPar(int &argc, char **&argv)
Initialize UPstream for a parallel run.
Definition: parRun.H:211
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:441
virtual ~argList()
Destructor.
Definition: argList.C:2241
static int tuning_NBX_
Tuning parameters for non-blocking exchange (NBX)
Definition: UPstream.H:973
bool allowFunctionObjects() const
The controlDict &#39;functions&#39; entry is allowed to be used.
Definition: argList.C:2252
static bool warnAboutAge(const int version) noexcept
Test if an age warning should be emitted.
Definition: error.C:67
simpleObjectRegistry & optimisationObjects()
Access to registered OptimisationSwitch objects.
Definition: debug.C:310
static void printHostsSubscription(const UList< string > &hostProcs)
Definition: argList.C:226
static void gatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
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:1243
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:485
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:862
static int nProcsNonblockingExchange
Number of processors to change to nonBlocking consensual exchange (NBX). Ignored for zero or negative...
Definition: UPstream.H:953
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:2270
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:2355
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). It is 1 for serial run. ...
Definition: UPstream.H:1602
static void warnLocalBoundaryConsistencyCompat(const dictionary &)
Warn about keyword changes for local boundary consistency checks.
Definition: FieldBase.C:77
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:958
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
Definition: UPstream.C:61
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:260
"scheduled" (MPI standard) : (MPI_Send, MPI_Recv)
static void recv(Type &value, const int fromProcNo, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, IOstreamOption::streamFormat fmt=IOstreamOption::BINARY)
Receive and deserialize a value. Uses operator>> for de-serialization.
Definition: IPstream.H:80
static void printTopoControl(Ostream &os)
Report the topology routines settings.
Definition: UPstream.C:100
static bool bannerEnabled()
Banner status (enabled/disabled).
Definition: argList.C:511
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:518
Extract command arguments and options from the supplied argc and argv parameters. ...
Definition: argList.H:118
static labelList matching(const wordRe &select, const UList< StringType > &input, const bool invert=false)
Determine the list indices for all matches.
static Istream & input(Istream &is, IntRange< T > &range)
Definition: IntRanges.C:33
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1596
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:193
static void set(bool verbose=false)
Activate SIGQUIT signal handler.
bool push_back(const fileName &libName)
Add to the list of names, but do not yet open.
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:364
static int maxFileModificationPolls
Max number of times to poll for file modification changes.
Definition: IOobject.H:361
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:399
string userName()
Return the user&#39;s login name.
Definition: POSIX.C:424
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:446
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:587
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:67
#define DetailInfo
Definition: evalEntry.C:30
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
static void noCheckProcessorDirectories()
Disable checking of processor directories.
Definition: argList.C:618
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:105
string hostName()
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:373
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:316
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:195
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:534
static int cacheLevel() noexcept
Return cache level.
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:211
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:351
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:674
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:328
static void set(bool verbose=false)
Activate SIGINT signal handler.
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:661
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:879
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:963
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:612
void stop()
Job end with "normal" termination.
Definition: JobInfo.C:228
static fileName envGlobalPath()
Global case (directory) from environment variable.
Definition: argList.C:667
void incrDryRun(int i=1) noexcept
Increase the dry-run level.
Definition: parRun.H:120
static word defaultFileHandler
Name of the default fileHandler.
static bool argsMandatory()
Command arguments type (optional/mandatory).
Definition: argList.C:499
bool setOption(const word &optName, const string &param="")
Set option directly (use with caution)
Definition: argList.C:2306
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 void send(const Type &value, const int communicator=UPstream::worldComm)
Serialize a value and broadcast (root == UPstream::masterNo()). Uses operator<< for serialization...
Definition: OPstream.H:161
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
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:365
fileName cwd()
The physical or logical current working directory path name.
Definition: POSIX.C:592
JobInfo jobInfo
Definition: JobInfo.C:45
::Foam::direction rank(const expressions::valueTypeCode) noexcept
The vector-space rank associated with given valueTypeCode.
Definition: exprTraits.C:70
messageStream Info
Information stream (stdout output on master, null elsewhere)
static void noBanner()
Disable emitting the banner information.
Definition: argList.C:505
static Ostream & writeBanner(Ostream &os, const bool noSyntaxHint=false)
Write the standard OpenFOAM file/dictionary banner.
void incrVerbose(int i=1) noexcept
Increase the verbosity level.
Definition: parRun.H:140
dictionary & optimisationSwitches()
The OptimisationSwitches sub-dictionary in the central controlDict(s).
Definition: debug.C:216
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:158
List< label > labelList
A List of labels.
Definition: List.H:61
static rangeType subProcs(const label communicator=worldComm)
Range of process indices for sub-processes.
Definition: UPstream.H:1727
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:1704
static void addUsage(const word &optName, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:460
static const wordList & allWorlds() noexcept
All worlds.
Definition: UPstream.H:1683
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:912
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
bool send()
Send buffer contents now and not in destructor [advanced usage]. Returns true on success.
Definition: OPstreams.C:84
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:592
label count(const UList< word > &optionNames) const
Return how many of the specified options were used.
Definition: argList.C:2278
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:358
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
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:2429
static void set(bool verbose=false)
Activate SIGSEGV signal handler.
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
readOption
Enumeration defining read preferences.