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