argList.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2026 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "argList.H"
27 #include "OSspecific.H"
28 #include "clock.H"
29 #include "IFstream.H"
30 #include "dictionary.H"
31 #include "IOobject.H"
32 #include "jobInfo.H"
33 #include "labelList.H"
34 #include "regIOobject.H"
35 #include "dynamicCode.H"
36 #include "fileOperation.H"
38 #include "stringListOps.H"
39 #include "dlLibraryTable.H"
40 
41 #include <cctype>
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
53 
55 {
57  (
58  "case", "dir",
59  "specify alternate case directory, default is the cwd"
60  );
61  argList::addBoolOption("parallel", "run in parallel");
62  validParOptions.set("parallel", "");
64  (
65  "roots", "(dir1 .. dirN)",
66  "slave root directories for distributed running"
67  );
68  validParOptions.set("roots", "(dir1 .. dirN)");
69 
71  (
72  "hostRoots", "((host1 dir1) .. (hostN dirN))",
73  "slave root directories (per host) for distributed running"
74  );
75  validParOptions.set("hostRoots", "((host1 dir1) .. (hostN dirN))");
76 
78  (
79  "fileHandler",
80  "handler",
81  "override the fileHandler"
82  );
84  (
85  "libs",
86  "'(\"lib1.so\" ... \"libN.so\")'",
87  "pre-load libraries"
88  );
89 
91 }
92 
93 
95 {
96  argList::removeOption("case");
97  argList::removeOption("parallel");
98  argList::removeOption("roots");
99  argList::removeOption("hostRoots");
100  argList::removeOption("fileHandler");
101  argList::removeOption("libs");
102 }
103 
104 
106 
107 
108 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
109 
111 (
112  const word& opt,
113  const string& usage
114 )
115 {
116  addOption(opt, "", usage);
117 }
118 
119 
121 (
122  const word& opt,
123  const string& param,
124  const string& usage
125 )
126 {
127  validOptions.set(opt, param);
128  if (!usage.empty())
129  {
130  optionUsage.set(opt, usage);
131  }
132 }
133 
134 
136 (
137  const word& opt,
138  const string& usage
139 )
140 {
141  if (usage.empty())
142  {
143  optionUsage.erase(opt);
144  }
145  else
146  {
147  optionUsage.set(opt, usage);
148  }
149 }
150 
151 
152 void Foam::argList::addNote(const string& note)
153 {
154  if (!note.empty())
155  {
156  notes.append(note);
157  }
158 }
159 
160 
162 {
163  validOptions.erase(opt);
164  optionUsage.erase(opt);
165 }
166 
167 
169 {
170  removeOption("parallel");
171  removeOption("roots");
172  removeOption("hostRoots");
173  validParOptions.clear();
174 }
175 
176 
177 void Foam::argList::printOptionUsage
178 (
179  const label location,
180  const string& str
181 )
182 {
183  const string::size_type textWidth = usageMax - usageMin;
184  const string::size_type strLen = str.size();
185 
186  if (strLen)
187  {
188  // Minimum of 2 spaces between option and usage:
189  if (string::size_type(location) + 2 <= usageMin)
190  {
191  for (string::size_type i = location; i < usageMin; ++i)
192  {
193  Info<<' ';
194  }
195  }
196  else
197  {
198  // or start a new line
199  Info<< nl;
200  for (string::size_type i = 0; i < usageMin; ++i)
201  {
202  Info<<' ';
203  }
204  }
205 
206  // Text wrap
208  while (pos != string::npos && pos + textWidth < strLen)
209  {
210  // Potential end point and next point
211  string::size_type curr = pos + textWidth - 1;
212  string::size_type next = string::npos;
213 
214  if (isspace(str[curr]))
215  {
216  // We were lucky: ended on a space
217  next = str.find_first_not_of(" \t\n", curr);
218  }
219  else if (isspace(str[curr+1]))
220  {
221  // The next one is a space - so we are okay
222  curr++; // otherwise the length is wrong
223  next = str.find_first_not_of(" \t\n", curr);
224  }
225  else
226  {
227  // Search for end of a previous word break
228  string::size_type prev = str.find_last_of(" \t\n", curr);
229 
230  // Reposition to the end of previous word if possible
231  if (prev != string::npos && prev > pos)
232  {
233  curr = prev;
234  }
235  }
236 
237  if (next == string::npos)
238  {
239  next = curr + 1;
240  }
241 
242  // Indent following lines (not the first one)
243  if (pos)
244  {
245  for (string::size_type i = 0; i < usageMin; ++i)
246  {
247  Info<<' ';
248  }
249  }
250 
251  Info<< str.substr(pos, (curr - pos)).c_str() << nl;
252  pos = next;
253  }
254 
255  // Output the remainder of the string
256  if (pos != string::npos)
257  {
258  // Indent following lines (not the first one)
259  if (pos)
260  {
261  for (string::size_type i = 0; i < usageMin; ++i)
262  {
263  Info<<' ';
264  }
265  }
266 
267  Info<< str.substr(pos).c_str() << nl;
268  }
269  }
270  else
271  {
272  Info<< nl;
273  }
274 }
275 
276 
277 bool Foam::argList::postProcess(int argc, char *argv[])
278 {
279  bool postProcessOption = false;
280 
281  for (int i=1; i<argc; i++)
282  {
283  postProcessOption = argv[i] == '-' + postProcessOptionName;
284  if (postProcessOption) break;
285  }
286 
287  return postProcessOption;
288 }
289 
290 
291 Foam::label Foam::argList::nArgs(int argc, char *argv[])
292 {
293  label n = 0;
294 
295  for (int i=1; i<argc; i++)
296  {
297  const string arg(argv[i]);
298  const string argName(arg(1, arg.size() - 1));
299 
300  if (arg[0] == '-' && validOptions.found(argName))
301  {
302  i += validOptions[argName].empty() ? 0 : 1;
303  }
304  else
305  {
306  n ++;
307  }
308  }
309 
310  return n;
311 }
312 
313 
314 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
315 
316 // Convert argv -> args_
317 // Transform sequences with "(" ... ")" into string lists in the process
318 bool Foam::argList::regroupArgv(int& argc, char**& argv)
319 {
320  int nArgs = 0;
321  int listDepth = 0;
322  string tmpString;
323 
324  // Note: we also re-write directly into args_
325  // and use a second pass to sort out args/options
326  for (int argi=0; argi<argc; argi++)
327  {
328  if (strcmp(argv[argi], "(") == 0)
329  {
330  ++listDepth;
331  tmpString += "(";
332  }
333  else if (strcmp(argv[argi], ")") == 0)
334  {
335  if (listDepth)
336  {
337  --listDepth;
338  tmpString += ")";
339  if (listDepth == 0)
340  {
341  args_[nArgs++] = tmpString;
342  tmpString.clear();
343  }
344  }
345  else
346  {
347  args_[nArgs++] = argv[argi];
348  }
349  }
350  else if (listDepth)
351  {
352  // Quote each string element
353  tmpString += "\"";
354  tmpString += argv[argi];
355  tmpString += "\"";
356  }
357  else
358  {
359  args_[nArgs++] = argv[argi];
360  }
361  }
362 
363  if (tmpString.size())
364  {
365  args_[nArgs++] = tmpString;
366  }
367 
368  args_.setSize(nArgs);
369 
370  return nArgs < argc;
371 }
372 
373 
374 void Foam::argList::getRootCase()
375 {
376  fileName casePath;
377 
378  // [-case dir] specified
379  HashTable<string>::const_iterator iter = options_.find("case");
380 
381  if (iter != options_.end())
382  {
383  casePath = iter();
384  casePath.clean();
385 
386  if (casePath.empty() || casePath == ".")
387  {
388  // Handle degenerate form and '-case .' like no -case specified
389  casePath = cwd();
390  options_.erase("case");
391  }
392  else if (!casePath.isAbsolute() && casePath.name() == "..")
393  {
394  // Avoid relative cases ending in '..' - makes for very ugly names
395  casePath = cwd()/casePath;
396  casePath.clean();
397  }
398  }
399  else
400  {
401  // Nothing specified, use the current dir
402  casePath = cwd();
403  }
404 
405  rootPath_ = casePath.path();
406  globalCase_ = casePath.name();
407  case_ = globalCase_;
408 
409 
410  // Set the case and case-name as an environment variable
411  if (rootPath_.isAbsolute())
412  {
413  // Absolute path - use as-is
414  setEnv("FOAM_CASE", rootPath_/globalCase_, true);
415  setEnv("FOAM_CASENAME", globalCase_, true);
416  }
417  else
418  {
419  // Qualify relative path
420  casePath = cwd()/rootPath_/globalCase_;
421  casePath.clean();
422 
423  setEnv("FOAM_CASE", casePath, true);
424  setEnv("FOAM_CASENAME", casePath.name(), true);
425  }
426 }
427 
428 
429 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
430 
432 (
433  int& argc,
434  char**& argv,
435  bool checkArgs,
436  bool checkOpts,
437  const bool initialise
438 )
439 :
440  args_(argc),
441  options_(argc)
442 {
443  // Pre-load any libraries
444  {
445  const string libsString(getEnv("FOAM_LIBS"));
446  if (!libsString.empty())
447  {
448  libs.open(fileNameList((IStringStream(libsString))()));
449  }
450 
451  for (int argi=0; argi<argc; argi++)
452  {
453  if (argv[argi][0] == '-')
454  {
455  const char *optionName = &argv[argi][1];
456  if (string(optionName) == "libs")
457  {
458  libs.open(fileNameList((IStringStream(argv[argi+1]))()));
459  break;
460  }
461  }
462  }
463  }
464 
465  // Check for fileHandler
466  word handlerType(getEnv("FOAM_FILEHANDLER"));
467  for (int argi=0; argi<argc; argi++)
468  {
469  if (argv[argi][0] == '-')
470  {
471  const char *optionName = &argv[argi][1];
472  if (string(optionName) == "fileHandler")
473  {
474  handlerType = argv[argi+1];
475  break;
476  }
477  }
478  }
479  if (handlerType.empty())
480  {
481  handlerType = fileOperation::defaultFileHandler;
482  }
483 
484  // Detect any parallel options
486  (
487  handlerType,
488  argc,
489  argv
490  )().needsThreading();
491 
492 
493  // Check if this run is a parallel run by searching for any parallel option
494  // If found call runPar which might filter argv
495  for (int argi=0; argi<argc; argi++)
496  {
497  if (argv[argi][0] == '-')
498  {
499  const char *optionName = &argv[argi][1];
500 
501  if (validParOptions.found(optionName))
502  {
503  parRunControl_.runPar(argc, argv, needsThread);
504  break;
505  }
506  }
507  }
508 
509  // Convert argv -> args_ and capture ( ... ) lists
510  // for normal arguments and for options
511  regroupArgv(argc, argv);
512 
513  // Get executable name
514  args_[0] = fileName(argv[0]);
515  executable_ = fileName(argv[0]).name();
516 
517  // Check arguments and options, we already have argv[0]
518  int nArgs = 1;
519  argListStr_ = args_[0];
520 
521  for (int argi=1; argi<args_.size(); argi++)
522  {
523  argListStr_ += ' ';
524  argListStr_ += args_[argi];
525 
526  if (args_[argi][0] == '-')
527  {
528  const char *optionName = &args_[argi][1];
529 
530  if
531  (
532  (
533  validOptions.found(optionName)
534  && !validOptions[optionName].empty()
535  )
536  || (
537  validParOptions.found(optionName)
538  && !validParOptions[optionName].empty()
539  )
540  )
541  {
542  ++argi;
543  if (argi >= args_.size())
544  {
545  FatalError
546  <<"Option '-" << optionName
547  << "' requires an argument" << endl;
548  printUsage();
549  FatalError.exit();
550  }
551 
552  argListStr_ += ' ';
553  argListStr_ += args_[argi];
554  options_.insert(optionName, args_[argi]);
555  }
556  else
557  {
558  options_.insert(optionName, "");
559  }
560  }
561  else
562  {
563  if (nArgs != argi)
564  {
565  args_[nArgs] = args_[argi];
566  }
567  ++nArgs;
568  }
569  }
570 
571  args_.setSize(nArgs);
572 
573  parse(checkArgs, checkOpts, initialise);
574 }
575 
576 
578 (
579  const argList& args,
580  const HashTable<string>& options,
581  bool checkArgs,
582  bool checkOpts,
583  bool initialise
584 )
585 :
586  parRunControl_(args.parRunControl_),
587  args_(args.args_),
588  options_(options),
589  executable_(args.executable_),
590  rootPath_(args.rootPath_),
591  globalCase_(args.globalCase_),
592  case_(args.case_),
593  argListStr_(args.argListStr_)
594 {
595  parse(checkArgs, checkOpts, initialise);
596 }
597 
598 
600 (
601  bool checkArgs,
602  bool checkOpts,
603  bool initialise
604 )
605 {
606  // Help/documentation options:
607  // -help print the usage
608  // -doc display application documentation in browser
609  // -srcDoc display source code in browser
610  if
611  (
612  options_.found("help")
613  || options_.found("doc")
614  || options_.found("srcDoc")
615  )
616  {
617  if (options_.found("help"))
618  {
619  printUsage();
620  }
621 
622  // Only display one or the other
623  if (options_.found("srcDoc"))
624  {
625  displayDoc(true);
626  }
627  else if (options_.found("doc"))
628  {
629  displayDoc(false);
630  }
631 
632  ::exit(0);
633  }
634 
635  // Print the usage message and exit if the number of arguments is incorrect
636  if (!check(checkArgs, checkOpts))
637  {
638  FatalError.exit();
639  }
640 
641 
642  if (initialise)
643  {
644  string dateString = clock::date();
645  string timeString = clock::clockTime();
646 
647  // Print the banner once only for parallel runs
649  {
651  << "Build : " << Foam::FOAMbuild << nl
652  << "Exec : " << argListStr_.c_str() << nl
653  << "Date : " << dateString.c_str() << nl
654  << "Time : " << timeString.c_str() << nl
655  << "Host : " << hostName() << nl
656  << "PID : " << pid() << endl;
657  }
658 
659  jobInfo_.add("startDate", dateString);
660  jobInfo_.add("startTime", timeString);
661  jobInfo_.add("userName", userName());
662  jobInfo_.add("foamVersion", word(FOAMversion));
663  jobInfo_.add("code", executable_);
664  jobInfo_.add("argList", argListStr_);
665  jobInfo_.add("currentDir", cwd());
666  jobInfo_.add("PPID", ppid());
667  jobInfo_.add("PGID", pgid());
668 
669  // Add build information - only use the first word
670  {
671  std::string build(Foam::FOAMbuild);
672  std::string::size_type found = build.find(' ');
673  if (found != std::string::npos)
674  {
675  build.resize(found);
676  }
677  jobInfo_.add("foamBuild", build);
678  }
679  }
680 
681 
682  // Set fileHandler. In increasing order of priority:
683  // 1. default = uncollated
684  // 2. environment var FOAM_FILEHANDLER
685  // 3. etc/controlDict optimisationSwitches 'fileHandler'
686  // 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)
687 
688  {
689  word handlerType(getEnv("FOAM_FILEHANDLER"));
690  HashTable<string>::const_iterator iter = options_.find("fileHandler");
691  if (iter != options_.end())
692  {
693  handlerType = iter();
694  }
695 
696  if (handlerType.empty())
697  {
698  handlerType = fileOperation::defaultFileHandler;
699  }
700 
701  autoPtr<fileOperation> handler
702  (
704  (
705  handlerType,
707  )
708  );
709  Foam::fileHandler(handler);
710  }
711 
712 
713  stringList slaveMachine;
714  stringList slaveProcs;
715 
716  // Collect slave machine/pid
717  if (parRunControl_.parRun())
718  {
719  if (Pstream::master())
720  {
721  slaveMachine.setSize(Pstream::nProcs() - 1);
722  slaveProcs.setSize(Pstream::nProcs() - 1);
723  label proci = 0;
724  for
725  (
726  int slave = Pstream::firstSlave();
727  slave <= Pstream::lastSlave();
728  slave++
729  )
730  {
731  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
732 
733  string slaveBuild;
734  label slavePid;
735  fromSlave >> slaveBuild >> slaveMachine[proci] >> slavePid;
736 
737  slaveProcs[proci] = slaveMachine[proci]+"."+name(slavePid);
738  proci++;
739 
740  // Check build string to make sure all processors are running
741  // the same build
742  if (slaveBuild != Foam::FOAMbuild)
743  {
744  FatalErrorIn(executable())
745  << "Master is running version " << Foam::FOAMbuild
746  << "; slave " << proci << " is running version "
747  << slaveBuild
748  << exit(FatalError);
749  }
750  }
751  }
752  else
753  {
754  OPstream toMaster
755  (
758  );
759  toMaster << string(Foam::FOAMbuild) << hostName() << pid();
760  }
761  }
762 
763 
764  // Case is a single processor run unless it is running parallel
765  int nProcs = 1;
766 
767  // Roots if running distributed
768  fileNameList roots;
769 
770  // If this actually is a parallel run
771  if (parRunControl_.parRun())
772  {
773  // For the master
774  if (Pstream::master())
775  {
776  // Establish rootPath_/globalCase_/case_ for master
777  getRootCase();
778 
779  // See if running distributed (different roots for different procs)
780  label dictNProcs = -1;
781  fileName source;
782 
783  if (options_.found("roots"))
784  {
785  source = "-roots";
786  IStringStream is(options_["roots"]);
787  roots = readList<fileName>(is);
788 
789  if (roots.size() != 1)
790  {
791  dictNProcs = roots.size()+1;
792  }
793  }
794  else if (options_.found("hostRoots"))
795  {
796  source = "-hostRoots";
797  IStringStream is(options_["hostRoots"]);
798  List<Tuple2<wordRe, fileName>> hostRoots(is);
799 
800  roots.setSize(Pstream::nProcs()-1);
801  forAll(hostRoots, i)
802  {
803  const Tuple2<wordRe, fileName>& hostRoot = hostRoots[i];
804  const wordRe& re = hostRoot.first();
805  labelList matchedRoots(findStrings(re, slaveMachine));
806  forAll(matchedRoots, matchi)
807  {
808  label slavei = matchedRoots[matchi];
809  if (roots[slavei] != wordRe())
810  {
812  << "Slave " << slaveMachine[slavei]
813  << " has multiple matching roots in "
814  << hostRoots << exit(FatalError);
815  }
816  else
817  {
818  roots[slavei] = hostRoot.second();
819  }
820  }
821  }
822 
823  // Check
824  forAll(roots, slavei)
825  {
826  if (roots[slavei] == wordRe())
827  {
829  << "Slave " << slaveMachine[slavei]
830  << " has no matching roots in "
831  << hostRoots << exit(FatalError);
832  }
833  }
834 
835  if (roots.size() != 1)
836  {
837  dictNProcs = roots.size()+1;
838  }
839  }
840  else
841  {
842  source = rootPath_/globalCase_/"system/decomposeParDict";
843  IFstream decompDictStream(source);
844 
845  if (!decompDictStream.good())
846  {
847  // Assume non-distributed running
848  dictNProcs = Pstream::nProcs();
849  }
850  else
851  {
852  dictionary decompDict(decompDictStream);
853 
854  dictNProcs = decompDict.lookup<label>("numberOfSubdomains");
855 
856  if (decompDict.lookupOrDefault("distributed", false))
857  {
858  decompDict.lookup("roots") >> roots;
859  }
860  }
861  }
862 
863  // Convenience:
864  // when a single root is specified, use it for all processes
865  if (roots.size() == 1)
866  {
867  const fileName rootName(roots[0]);
868  roots.setSize(Pstream::nProcs()-1, rootName);
869 
870  // adjust dictNProcs for command-line '-roots' option
871  if (dictNProcs < 0)
872  {
873  dictNProcs = roots.size()+1;
874  }
875  }
876 
877 
878  // Check number of processors.
879  // nProcs => number of actual procs
880  // dictNProcs => number of procs specified in decompositionDict
881  // nProcDirs => number of processor directories
882  // (n/a when running distributed)
883  //
884  // - normal running : nProcs = dictNProcs = nProcDirs
885  // - decomposition to more processors : nProcs = dictNProcs
886  // - decomposition to fewer processors : nProcs = nProcDirs
887  if (dictNProcs > Pstream::nProcs())
888  {
889  FatalError
890  << source
891  << " specifies " << dictNProcs
892  << " processors but job was started with "
893  << Pstream::nProcs() << " processors."
894  << exit(FatalError);
895  }
896 
897 
898  // Distributed data
899  if (roots.size())
900  {
901  if (roots.size() != Pstream::nProcs()-1)
902  {
903  FatalError
904  << "number of entries in roots "
905  << roots.size()
906  << " is not equal to the number of slaves "
907  << Pstream::nProcs()-1
908  << exit(FatalError);
909  }
910 
911  forAll(roots, i)
912  {
913  roots[i].expand();
914  }
915 
916  // Distribute the master's argument list (with new root)
917  bool hadCaseOpt = options_.found("case");
918  for
919  (
920  int slave = Pstream::firstSlave();
921  slave <= Pstream::lastSlave();
922  slave++
923  )
924  {
925  options_.set("case", roots[slave-1]/globalCase_);
926 
928  toSlave << args_ << options_;
929  }
930  options_.erase("case");
931 
932  // Restore [-case dir]
933  if (hadCaseOpt)
934  {
935  options_.set("case", rootPath_/globalCase_);
936  }
937  }
938  else
939  {
940  // Possibly going to fewer processors.
941  // Check if all procDirs are there.
942  if (dictNProcs < Pstream::nProcs())
943  {
944  label nProcDirs = 0;
945  while
946  (
947  isDir
948  (
949  rootPath_/globalCase_/"processor"
950  + name(++nProcDirs)
951  )
952  )
953  {}
954 
955  if (nProcDirs != Pstream::nProcs())
956  {
957  FatalError
958  << "number of processor directories = "
959  << nProcDirs
960  << " is not equal to the number of processors = "
961  << Pstream::nProcs()
962  << exit(FatalError);
963  }
964  }
965 
966  // Distribute the master's argument list (unaltered)
967  for
968  (
969  int slave = Pstream::firstSlave();
970  slave <= Pstream::lastSlave();
971  slave++
972  )
973  {
975  toSlave << args_ << options_;
976  }
977  }
978  }
979  else
980  {
981  // Collect the master's argument list
982  IPstream fromMaster
983  (
986  );
987  fromMaster >> args_ >> options_;
988 
989  // Establish rootPath_/globalCase_/case_ for slave
990  getRootCase();
991  }
992 
993  nProcs = Pstream::nProcs();
994  case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
995  }
996  else
997  {
998  // Establish rootPath_/globalCase_/case_
999  getRootCase();
1000  case_ = globalCase_;
1001  }
1002 
1004  {
1005  Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
1006  << "nProcs : " << nProcs << endl;
1007 
1008  if (parRunControl_.parRun())
1009  {
1010  Info<< "Slaves : " << slaveProcs << nl;
1011  if (roots.size())
1012  {
1013  Info<< "Roots : " << roots << nl;
1014  }
1015  Info<< "Pstream initialised with:" << nl
1016  << " floatTransfer : " << Pstream::floatTransfer << nl
1017  << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
1018  << " commsType : "
1020  << " polling iterations : " << Pstream::nPollProcInterfaces
1021  << endl;
1022  }
1023  }
1024 
1025  if (initialise)
1026  {
1027  jobInfo_.add("root", rootPath_);
1028  jobInfo_.add("case", globalCase_);
1029  jobInfo_.add("nProcs", nProcs);
1030  if (slaveProcs.size())
1031  {
1032  jobInfo_.add("slaves", slaveProcs);
1033  }
1034  if (roots.size())
1035  {
1036  jobInfo_.add("roots", roots);
1037  }
1038  jobInfo_.write(executable_, rootPath_/globalCase_);
1039 
1040  // Switch on signal trapping. We have to wait until after Pstream::init
1041  // since this sets up its own ones.
1042  sigFpe_.set(writeInfoHeader);
1043  sigInt_.set(writeInfoHeader);
1044  sigQuit_.set(writeInfoHeader);
1045  sigSegv_.set(writeInfoHeader);
1046 
1047  if (writeInfoHeader)
1048  {
1049  Info<< "fileModificationChecking : "
1050  << "Monitoring run-time modified files using "
1052  [
1054  ];
1055  if
1056  (
1057  (
1060  )
1061  || (
1064  )
1065  )
1066  {
1067  Info<< " (fileModificationSkew "
1069  }
1070  Info<< endl;
1071 
1072  Info<< "allowSystemOperations : ";
1074  {
1075  Info<< "Allowing user-supplied system call operations" << endl;
1076  }
1077  else
1078  {
1079  Info<< "Disallowing user-supplied system call operations"
1080  << endl;
1081  }
1082  }
1083 
1085  {
1086  Info<< endl;
1088  }
1089  }
1090 }
1091 
1092 
1093 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1094 
1096 {
1097  jobInfo_.end();
1098 
1099  // Delete file handler to flush any remaining IO
1100  autoPtr<fileOperation> dummy(nullptr);
1101  fileHandler(dummy);
1102 }
1103 
1104 
1105 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1106 
1107 bool Foam::argList::setOption(const word& opt, const string& param)
1108 {
1109  bool changed = false;
1110 
1111  // Only allow valid options
1112  if (validOptions.found(opt))
1113  {
1114  // Some options are to be protected
1115  if
1116  (
1117  opt == "case"
1118  || opt == "parallel"
1119  || opt == "roots"
1120  || opt == "hostRoots"
1121  )
1122  {
1123  FatalError
1124  <<"used argList::setOption on a protected option: '"
1125  << opt << "'" << endl;
1126  FatalError.exit();
1127  }
1128 
1129  if (validOptions[opt].empty())
1130  {
1131  // Bool option
1132  if (!param.empty())
1133  {
1134  // Disallow change of type
1135  FatalError
1136  <<"used argList::setOption to change bool to non-bool: '"
1137  << opt << "'" << endl;
1138  FatalError.exit();
1139  }
1140  else
1141  {
1142  // Did not previously exist
1143  changed = !options_.found(opt);
1144  }
1145  }
1146  else
1147  {
1148  // Non-bool option
1149  if (param.empty())
1150  {
1151  // Disallow change of type
1152  FatalError
1153  <<"used argList::setOption to change non-bool to bool: '"
1154  << opt << "'" << endl;
1155  FatalError.exit();
1156  }
1157  else
1158  {
1159  // Existing value needs changing, or did not previously exist
1160  changed = options_.found(opt) ? options_[opt] != param : true;
1161  }
1162  }
1163  }
1164  else
1165  {
1166  FatalError
1167  <<"used argList::setOption on an invalid option: '"
1168  << opt << "'" << nl << "allowed are the following:"
1169  << validOptions << endl;
1170  FatalError.exit();
1171  }
1172 
1173  // Set/change the option as required
1174  if (changed)
1175  {
1176  options_.set(opt, param);
1177  }
1178 
1179  return changed;
1180 }
1181 
1182 
1184 {
1185  // Only allow valid options
1186  if (validOptions.found(opt))
1187  {
1188  // Some options are to be protected
1189  if
1190  (
1191  opt == "case"
1192  || opt == "parallel"
1193  || opt == "roots"
1194  || opt == "hostRoots"
1195  )
1196  {
1197  FatalError
1198  <<"used argList::unsetOption on a protected option: '"
1199  << opt << "'" << endl;
1200  FatalError.exit();
1201  }
1202 
1203  // Remove the option, return true if state changed
1204  return options_.erase(opt);
1205  }
1206  else
1207  {
1208  FatalError
1209  <<"used argList::unsetOption on an invalid option: '"
1210  << opt << "'" << nl << "allowed are the following:"
1211  << validOptions << endl;
1212  FatalError.exit();
1213  }
1214 
1215  return false;
1216 }
1217 
1218 
1220 {
1221  // Output notes directly - no automatic text wrapping
1222  if (!notes.empty())
1223  {
1224  Info<< nl;
1225  forAllConstIter(SLList<string>, notes, iter)
1226  {
1227  Info<< iter().c_str() << nl;
1228  }
1229  }
1230 }
1231 
1232 
1234 {
1235  Info<< nl << "Usage: " << executable_ << " [OPTIONS]";
1236 
1237  forAllConstIter(SLList<string>, validArgs, iter)
1238  {
1239  Info<< " <" << iter().c_str() << '>';
1240  }
1241 
1242  Info<< nl << "options:" << nl;
1243 
1244  wordList opts = validOptions.sortedToc();
1245  forAll(opts, optI)
1246  {
1247  const word& optionName = opts[optI];
1248 
1249  HashTable<string>::const_iterator iter = validOptions.find(optionName);
1250  Info<< " -" << optionName;
1251  label len = optionName.size() + 3; // Length includes leading ' -'
1252 
1253  if (iter().size())
1254  {
1255  // Length includes space and between option/param and '<>'
1256  if (iter()[0] == '\'')
1257  {
1258  len += iter().size() + 1;
1259  Info<< ' ' << iter().c_str();
1260  }
1261  else
1262  {
1263  len += iter().size() + 3;
1264  Info<< " <" << iter().c_str() << '>';
1265  }
1266  }
1267 
1269  optionUsage.find(optionName);
1270 
1271  if (usageIter != optionUsage.end())
1272  {
1273  printOptionUsage
1274  (
1275  len,
1276  usageIter()
1277  );
1278  }
1279  else
1280  {
1281  Info<< nl;
1282  }
1283  }
1284 
1285  // Place srcDoc/doc/help options at the end
1286  Info<< " -srcDoc";
1287  printOptionUsage
1288  (
1289  9,
1290  "display source code in browser"
1291  );
1292 
1293  Info<< " -doc";
1294  printOptionUsage
1295  (
1296  6,
1297  "display application documentation in browser"
1298  );
1299 
1300  Info<< " -help";
1301  printOptionUsage
1302  (
1303  7,
1304  "print the usage"
1305  );
1306 
1307 
1308  printNotes();
1309 
1310  Info<< nl
1311  <<"Using: OpenFOAM-" << Foam::FOAMversion
1312  << " (see https://openfoam.org)" << nl
1313  <<"Build: " << Foam::FOAMbuild << nl
1314  << endl;
1315 }
1316 
1317 
1318 void Foam::argList::displayDoc(bool source) const
1319 {
1320  const dictionary& docDict =
1322  (
1323  {"documentation", "Documentation"}
1324  );
1325  List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
1326  fileName docExt(docDict.lookup("doxySourceFileExt"));
1327 
1328  // For source code: change foo_8C.html to foo_8C_source.html
1329  if (source)
1330  {
1331  docExt.replace(".", "_source.");
1332  }
1333 
1334  fileName docFile;
1335  fileName httpServer;
1336  bool found = false;
1337 
1338  forAll(docDirs, dirI)
1339  {
1340  // An HTTP server is treated as a special case ...
1341  if (docDirs[dirI].component(0) == "http:")
1342  {
1343  httpServer = docDirs[dirI]/executable_ + docExt;
1344  }
1345  else
1346  {
1347  // ... all other entries are treated as local directories
1348 
1349  // Remove the optional "file://"
1350  if (docDirs[dirI].component(0) == "file:")
1351  {
1352  docDirs[dirI].replace("file://", string::null);
1353  }
1354 
1355 
1356  // Expand the file name
1357  docFile = docDirs[dirI]/executable_ + docExt;
1358  docFile.expand();
1359 
1360  // Check the existence of the file
1361  if (isFile(docFile))
1362  {
1363  found = true;
1364  break;
1365  }
1366  }
1367  }
1368 
1369  if (found || httpServer != fileName::null)
1370  {
1371  string docBrowser = getEnv("FOAM_DOC_BROWSER");
1372  if (docBrowser.empty())
1373  {
1374  docDict.lookup("docBrowser") >> docBrowser;
1375  }
1376 
1377  if (found)
1378  {
1379  docBrowser += " file://" + docFile;
1380  }
1381  else
1382  {
1383  docBrowser += " " + httpServer;
1384  }
1385 
1386  Info<< "Show documentation: " << docBrowser.c_str() << endl;
1387 
1388  system(docBrowser);
1389  }
1390  else
1391  {
1392  Info<< nl
1393  << "No documentation found for " << executable_
1394  << ", but you can use -help to display the usage\n" << endl;
1395  }
1396 }
1397 
1398 
1399 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
1400 {
1401  bool ok = true;
1402 
1403  if (Pstream::master())
1404  {
1405  if (checkArgs && args_.size() - 1 != validArgs.size())
1406  {
1407  FatalError
1408  << "Wrong number of arguments, expected " << validArgs.size()
1409  << " found " << args_.size() - 1 << endl;
1410  ok = false;
1411  }
1412 
1413  if (checkOpts)
1414  {
1415  forAllConstIter(HashTable<string>, options_, iter)
1416  {
1417  if
1418  (
1419  !validOptions.found(iter.key())
1420  && !validParOptions.found(iter.key())
1421  )
1422  {
1423  FatalError
1424  << "Invalid option: -" << iter.key() << endl;
1425  ok = false;
1426  }
1427  }
1428  }
1429 
1430  if (!ok)
1431  {
1432  printUsage();
1433  }
1434  }
1435 
1436  return ok;
1437 }
1438 
1439 
1441 {
1442  if (!fileHandler().isDir(rootPath()))
1443  {
1444  FatalError
1445  << executable_
1446  << ": cannot open root directory " << rootPath()
1447  << endl;
1448 
1449  return false;
1450  }
1451 
1452  fileName pathDir(fileHandler().filePath(path()));
1453 
1454  if (pathDir.empty() && Pstream::master())
1455  {
1456  // Allow slaves on non-existing processor directories, created later
1457  // (e.g. redistributePar)
1458  FatalError
1459  << executable_
1460  << ": cannot open case directory " << path()
1461  << endl;
1462 
1463  return false;
1464  }
1465 
1466  return true;
1467 }
1468 
1469 
1470 // ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
bool found
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
Foam::argList::initValidTables dummyInitValidTables
Definition: argList.C:105
An STL-conforming const_iterator.
Definition: HashTable.H:494
friend class const_iterator
Declare friendship with the const_iterator.
Definition: HashTable.H:197
Input from file stream.
Definition: IFstream.H:85
static Stream & writeBanner(Stream &os, bool noHint=false)
Write the standard OpenFOAM file/dictionary banner.
Definition: IOobjectI.H:45
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:223
static Stream & writeDivider(Stream &os)
Write the standard file section divider.
Definition: IOobjectI.H:93
static const NamedEnum< fileCheckTypes, 4 > fileCheckTypesNames
Definition: IOobject.H:140
Input inter-processor communications stream.
Definition: IPstream.H:54
Input from memory buffer stream.
Definition: IStringStream.H:52
bool good() const
Return true if next operation might succeed.
Definition: Istream.H:101
Template class for non-intrusive linked lists.
Definition: LList.H:76
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output inter-processor communications stream.
Definition: OPstream.H:54
void runPar(int &argc, char **&argv, const bool needsThread)
Definition: parRun.H:66
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
const Type1 & first() const
Return first.
Definition: Tuple2.H:119
static int masterNo()
Process index of the master.
Definition: UPstream.H:417
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static bool floatTransfer
Should compact transfer be used in which floats replace doubles.
Definition: UPstream.H:265
static const NamedEnum< commsTypes, 3 > commsTypeNames
Definition: UPstream.H:71
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:452
static int nProcsSimpleSum
Number of processors at which the sum algorithm changes from linear.
Definition: UPstream.H:269
static int nPollProcInterfaces
Number of polling cycles in processor updates.
Definition: UPstream.H:275
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static void addValidParOptions(HashTable< string > &validParOptions)
Add the valid option this type of communications library.
Definition: UPstream.C:31
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:446
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:272
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static void clear()
Clear the options table.
Definition: argList.C:94
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:103
void parse(bool checkArgs, bool checkOpts, bool initialise)
Parse.
Definition: argList.C:600
static word postProcessOptionName
Standard name for the post-processing option.
Definition: argList.H:174
static label nArgs(int argc, char *argv[])
Return the number of arguments (not options)
Definition: argList.C:291
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:121
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:152
const string & arg(const label index) const
Return the argument corresponding to index.
Definition: argListI.H:84
static void removeOption(const word &opt)
Remove option from validOptions and from optionUsage.
Definition: argList.C:161
static HashTable< string > validParOptions
A list of valid parallel options.
Definition: argList.H:159
bool setOption(const word &opt, const string &param="")
Set option directly (use with caution)
Definition: argList.C:1107
static bool postProcess(int argc, char *argv[])
Return true if the post-processing option is specified.
Definition: argList.C:277
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:111
virtual ~argList()
Destructor.
Definition: argList.C:1095
static HashTable< string > optionUsage
Short usage information for validOptions.
Definition: argList.H:162
static string::size_type usageMin
Min offset for displaying usage (default: 20)
Definition: argList.H:168
argList(int &argc, char **&argv, bool checkArgs=true, bool checkOpts=true, bool initialise=true)
Construct from argc and argv.
Definition: argList.C:432
static SLList< string > notes
Additional notes for usage.
Definition: argList.H:165
bool checkRootCase() const
Check root path and case path.
Definition: argList.C:1440
void displayDoc(bool source=false) const
Display documentation in browser.
Definition: argList.C:1318
static void noParallel()
Remove the parallel options.
Definition: argList.C:168
static string::size_type usageMax
Max screen width for displaying usage (default: 80)
Definition: argList.H:171
bool unsetOption(const word &opt)
Unset option directly (use with caution)
Definition: argList.C:1183
void printNotes() const
Print notes (if any)
Definition: argList.C:1219
static HashTable< string > validOptions
A list of valid options.
Definition: argList.H:156
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:153
static void addUsage(const word &opt, const string &usage)
Add option usage information to optionUsage.
Definition: argList.C:136
bool check(bool checkArgs=true, bool checkOpts=true) const
Check argument list.
Definition: argList.C:1399
void printUsage() const
Print usage.
Definition: argList.C:1233
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
static string clockTime()
Return the current wall-clock time as a string.
Definition: clock.C:93
static string date()
Return the current wall-clock date as a string.
Definition: clock.C:77
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
const dictionary & subDictBackwardsCompatible(const wordList &) const
Find and return a sub-dictionary, trying a list of keywords in.
Definition: dictionary.C:809
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
bool add(entry *, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:1019
bool open(const fileName &libName, const bool verbose=true)
Open the named library, optionally with warnings if problems occur.
static int allowSystemOperations
Flag if system operations are allowed.
Definition: dynamicCode.H:188
void exit(const int errNo=1)
Exit : can be called for any error to exit program.
Definition: error.C:125
A class for handling file names.
Definition: fileName.H:82
bool isAbsolute() const
Return true if file name is absolute.
Definition: fileName.C:73
bool clean()
Cleanup file name.
Definition: fileName.C:93
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
static const fileName null
An empty fileName.
Definition: fileName.H:97
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:284
static autoPtr< fileOperation > New(const word &type, const bool verbose)
Select type.
static word defaultFileHandler
Default fileHandler.
static autoPtr< fileOperationInitialise > New(const word &type, int &argc, char **&argv)
Select type.
static float fileModificationSkew
Definition: regIOobject.H:100
A class for handling character strings derived from std::string.
Definition: string.H:79
static const string null
An empty string.
Definition: string.H:88
string & replace(const string &oldStr, const string &newStr, size_type start=0)
In this string replace first occurrence of sub-string oldStr.
Definition: string.C:64
string & expand(const bool allowEmpty=false)
Expand initial tildes and all occurrences of environment variables.
Definition: string.C:125
A wordRe is a word, but can also have a regular expression for matching words.
Definition: wordRe.H:77
A class for handling words, derived from string.
Definition: word.H:63
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:329
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
const dimensionedScalar re
Classical electron radius: default SI units: [m].
dictionary & configDict()
The central control dictionary.
Definition: debug.C:117
bool isFile(const fileName &, const bool checkVariants=true, const bool followLink=true)
Does the name exist as a file in the file system?
Definition: POSIX.C:555
const fileOperation & fileHandler()
Get current file handler.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
dlLibraryTable libs
Table of loaded dynamic libraries.
fileName cwd()
Return current working directory path name.
Definition: POSIX.C:241
int system(const std::string &command)
Execute the specified command.
Definition: POSIX.C:1230
dimensionedScalar pos(const dimensionedScalar &ds)
bool setEnv(const word &name, const std::string &value, const bool overwrite)
Set an environment variable.
Definition: POSIX.C:115
List< fileName > fileNameList
A List of fileNames.
Definition: fileNameList.H:50
const char *const FOAMbuild
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
bool findStrings(const wordReListMatcher &matcher, const std::string &str)
Return true if string matches one of the regular expressions.
Definition: stringListOps.H:52
jobInfo jobInfo_
Definition: jobInfo.C:44
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
bool writeInfoHeader
const char *const FOAMversion
messageStream Info
string userName()
Return the user's login name.
Definition: POSIX.C:165
pid_t pgid()
Return the group PID of this process.
Definition: POSIX.C:85
string hostName(const bool full=false)
Return the system's host name, as per hostname(1)
Definition: POSIX.C:125
void component(GeometricField< typename GeometricField< Type, GeoMesh, PrimitiveField1 >::cmptType, GeoMesh, PrimitiveField1 > &gcf, const GeometricField< Type, GeoMesh, PrimitiveField2 > &gf, const direction d)
pid_t ppid()
Return the parent PID of this process.
Definition: POSIX.C:79
bool isDir(const fileName &, const bool followLink=true)
Does the name exist as a directory in the file system?
Definition: POSIX.C:539
string getEnv(const word &)
Return environment variable of given name.
Definition: POSIX.C:97
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
pid_t pid()
Return the PID of this process.
Definition: POSIX.C:73
error FatalError
bool isspace(char c)
Definition: char.H:53
static const char nl
Definition: Ostream.H:297
Foam::argList args(argc, argv)
Operations on lists of strings.