1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
27 #include "OSspecific.H"
30 #include "dictionary.H"
34 #include "labelList.H"
35 #include "SortableList.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 Foam::SLList<Foam::string> Foam::argList::validArgs;
40 Foam::HashTable<Foam::string> Foam::argList::validOptions;
41 Foam::HashTable<Foam::string> Foam::argList::validParOptions;
42 Foam::word Foam::argList::appDictName_("");
43 bool Foam::argList::bannerEnabled(true);
46 Foam::argList::initValidTables::initValidTables()
48 validOptions.set("case", "dir");
49 validOptions.set("parallel", "");
50 validParOptions.set("parallel", "");
51 validOptions.set("noFunctionObjects", "");
53 // Add the parameters for modifying the controlDict
54 // switches from the command-line
56 // Instantiate a NamedEnum for the controlDict switches names
59 debug::globalControlDictSwitchSet,
60 debug::DIM_GLOBAL_CONTROL_DICT_SWITCH_SET
62 globalControlDictSwitchSetNames;
64 forAll (globalControlDictSwitchSetNames, gI)
66 word switchSetName = globalControlDictSwitchSetNames.names[gI];
67 validOptions.set(switchSetName, "key1=val1,key2=val2,...");
70 validOptions.set("dumpControlSwitches", "");
72 Pstream::addValidParOptions(validParOptions);
76 Foam::argList::initValidTables dummyInitValidTables;
79 // convert argv -> args_
80 // transform sequences with "(" ... ")" into string lists in the process
81 bool Foam::argList::regroupArgv(int& argc, char**& argv)
87 // note: we also re-write directly into args_
88 // and use a second pass to sort out args/options
89 for (int argI = 0; argI < argc; argI++)
91 if (strcmp(argv[argI], "(") == 0)
96 else if (strcmp(argv[argI], ")") == 0)
104 args_[nArgs++] = tmpString;
110 args_[nArgs++] = argv[argI];
115 // quote each string element
117 tmpString += argv[argI];
122 args_[nArgs++] = argv[argI];
126 if (tmpString.size())
128 args_[nArgs++] = tmpString;
131 args_.setSize(nArgs);
137 // get rootPath_/globalCase_ from one of the following forms
141 // Also export FOAM_CASE and FOAM_CASENAME environment variables
142 // so they can be used immediately (eg, in decomposeParDict)
144 void Foam::argList::getRootCase()
148 // [-case dir] specified
149 HashTable<string>::iterator iter = options_.find("case");
151 if (iter != options_.end())
156 if (casePath.empty() || casePath == ".")
158 // handle degenerate form and '-case .' like no -case specified
160 options_.erase("case");
162 else if (casePath[0] != '/' && casePath.name() == "..")
164 // avoid relative cases ending in '..' - makes for very ugly names
165 casePath = cwd()/casePath;
171 // nothing specified, use the current dir
175 rootPath_ = casePath.path();
176 globalCase_ = casePath.name();
179 // Set the case and case-name as an environment variable
180 if (rootPath_[0] == '/')
182 // Absolute path - use as-is
183 setEnv("FOAM_CASE", rootPath_/globalCase_, true);
184 setEnv("FOAM_CASENAME", globalCase_, true);
188 // Qualify relative path
189 fileName casePath = cwd()/rootPath_/globalCase_;
192 setEnv("FOAM_CASE", casePath, true);
193 setEnv("FOAM_CASENAME", casePath.name(), true);
198 Foam::stringList::subList Foam::argList::additionalArgs() const
200 return stringList::subList(args_, args_.size() - 1, 1);
204 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
206 Foam::argList::argList
217 // Check if this run is a parallel run by searching for any parallel option
218 // If found call runPar (might filter argv)
219 for (int argI = 0; argI < argc; argI++)
221 if (argv[argI][0] == '-')
223 const char *optionName = &argv[argI][1];
225 if (validParOptions.found(optionName))
227 parRunControl_.runPar(argc, argv);
233 // convert argv -> args_ and capture ( ... ) lists
234 // for normal arguments and for options
235 regroupArgv(argc, argv);
237 // Get executable name
238 args_[0] = fileName(argv[0]);
239 executable_ = fileName(argv[0]).name();
241 // Check arguments and options, we already have argv[0]
243 string argListString = args_[0];
245 for (int argI = 1; argI < args_.size(); argI++)
247 argListString += ' ';
248 argListString += args_[argI];
250 if (args_[argI][0] == '-')
252 const char *optionName = &args_[argI][1];
257 validOptions.found(optionName)
258 && validOptions[optionName] != ""
261 validParOptions.found(optionName)
262 && validParOptions[optionName] != ""
267 if (argI >= args_.size())
270 << "option " << "'-" << optionName << '\''
271 << " requires an argument"
275 argListString += ' ';
276 argListString += args_[argI];
277 options_.insert(optionName, args_[argI]);
281 options_.insert(optionName, "");
288 args_[nArgs] = args_[argI];
294 args_.setSize(nArgs);
296 // Help/documentation options:
297 // -help print the usage
298 // -doc display application documentation in browser
299 // -srcDoc display source code in browser
302 options_.found("help")
303 || options_.found("doc")
304 || options_.found("srcDoc")
307 if (options_.found("help"))
312 // only display one or the other
313 if (options_.found("srcDoc"))
317 else if (options_.found("doc"))
325 // Print the usage message and exit if the number of arguments is incorrect
326 if (!check(checkArgs, checkOpts))
331 // From here, we consider the command-line arguments to be valid
333 string dateString = clock::date();
334 string timeString = clock::clockTime();
335 fileName ctrlDict = debug::controlDict().name();
336 string ctrlDictString = ctrlDict.path()/ctrlDict.name();
338 // Print the banner once only for parallel runs
339 if (Pstream::master() && bannerEnabled)
341 IOobject::writeBanner(Info, true)
342 << "Build : " << Foam::FOAMbuild << nl
343 << "Exec : " << argListString.c_str() << nl
344 << "Date : " << dateString.c_str() << nl
345 << "Time : " << timeString.c_str() << nl
346 << "Host : " << hostName() << nl
351 jobInfo.add("startDate", dateString);
352 jobInfo.add("startTime", timeString);
353 jobInfo.add("userName", userName());
354 jobInfo.add("foamVersion", word(FOAMversion));
355 jobInfo.add("foamBuild", Foam::FOAMbuild);
356 jobInfo.add("code", executable_);
357 jobInfo.add("argList", argListString);
358 jobInfo.add("currentDir", cwd());
359 jobInfo.add("PPID", ppid());
360 jobInfo.add("PGID", pgid());
363 // Case is a single processor run unless it is running parallel
366 // If this actually is a parallel run
367 if (parRunControl_.parRun())
370 if (Pstream::master())
372 // establish rootPath_/globalCase_/case_ for master
375 IFstream decompDictStream
377 rootPath_/globalCase_/"system/decomposeParDict"
380 if (!decompDictStream.good())
384 << decompDictStream.name()
388 dictionary decompDict(decompDictStream);
394 decompDict.lookup("numberOfSubdomains")
398 // Check number of processors.
399 // nProcs => number of actual procs
400 // dictNProcs => number of procs specified in decompositionDict
401 // nProcDirs => number of processor directories
402 // (n/a when running distributed)
404 // - normal running : nProcs = dictNProcs = nProcDirs
405 // - decomposition to more processors : nProcs = dictNProcs
406 // - decomposition to fewer processors : nProcs = nProcDirs
407 if (dictNProcs > Pstream::nProcs())
410 << decompDictStream.name()
411 << " specifies " << dictNProcs
412 << " processors but job was started with "
413 << Pstream::nProcs() << " processors."
418 if (decompDict.lookupOrDefault<Switch>("distributed", false))
421 decompDict.lookup("roots") >> roots;
423 if (roots.size() != Pstream::nProcs() - 1)
426 << "number of entries in decompositionDict::roots"
427 << " is not equal to the number of slaves "
428 << Pstream::nProcs() - 1
432 // Distribute the master's argument list (with new root)
433 bool hadCaseOpt = options_.found("case");
436 int slave = Pstream::firstSlave();
437 slave <= Pstream::lastSlave();
444 fileName(roots[slave-1])/globalCase_
447 OPstream toSlave(Pstream::scheduled, slave);
448 toSlave << args_ << options_;
450 options_.erase("case");
452 // restore [-case dir]
455 options_.set("case", rootPath_/globalCase_);
460 // Possibly going to fewer processors.
461 // Check if all procDirs are there.
462 if (dictNProcs < Pstream::nProcs())
469 rootPath_/globalCase_/"processor"
475 if (nProcDirs != Pstream::nProcs())
478 << "number of processor directories = "
480 << " is not equal to the number of processors = "
486 // Distribute the master's argument list (unaltered)
489 int slave = Pstream::firstSlave();
490 slave <= Pstream::lastSlave();
494 OPstream toSlave(Pstream::scheduled, slave);
495 toSlave << args_ << options_;
501 // Collect the master's argument list
502 IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
503 fromMaster >> args_ >> options_;
505 // establish rootPath_/globalCase_/case_ for slave
509 nProcs = Pstream::nProcs();
510 case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
514 // establish rootPath_/globalCase_/case_
519 // Managing the overrides for the global control switches:
521 // Here is the order of precedence for the definition/overriding of the
522 // control switches, from lowest to highest:
523 // - source code definitions from the various libraries/solvers
524 // - file specified by the env. variable FOAM_GLOBAL_CONTROLDICT
525 // - case's system/controlDict file
526 // - command-line parameters
528 // First, we allow the users to specify the location of a centralized
529 // global controlDict dictionary using the environment variable
530 // FOAM_GLOBAL_CONTROLDICT.
531 fileName optionalGlobControlDictFileName =
532 getEnv("FOAM_GLOBAL_CONTROLDICT");
534 if (optionalGlobControlDictFileName.size() )
536 debug::updateCentralDictVars
538 optionalGlobControlDictFileName,
539 Pstream::master() && bannerEnabled
543 // Now that the rootPath_/globalCase_ directory is known (following the
544 // call to getRootCase()), we grab any global control switches overrides
545 // from the current case's controlDict.
547 debug::updateCentralDictVars
549 rootPath_/globalCase_/"system/controlDict",
550 Pstream::master() && bannerEnabled
553 // Finally, a command-line override for central controlDict's variables.
554 // This is the ultimate override for the global control switches.
556 // Instantiate a NamedEnum for the controlDict switches names
559 debug::globalControlDictSwitchSet,
560 debug::DIM_GLOBAL_CONTROL_DICT_SWITCH_SET
562 globalControlDictSwitchSetNames;
564 forAll (globalControlDictSwitchSetNames, gI)
566 word switchSetName = globalControlDictSwitchSetNames.names[gI];
568 if (optionFound(switchSetName))
570 debug::updateCentralDictVars
572 globalControlDictSwitchSetNames[switchSetName],
573 option(switchSetName)
578 if ( optionFound("dumpControlSwitches") )
580 if (Pstream::master())
582 // Dumping the application's control switches.
583 // We dump the full information to the console using a standard
584 // dictionary format, so one can copy/paste this information
585 // directly into a case's system/controlDict file to
586 // override some switches values without having to always
587 // use the command-line options.
588 debug::dumpControlSwitchesToConsole();
596 // collect slave machine/pid
597 if (parRunControl_.parRun())
599 if (Pstream::master())
601 slaveProcs.setSize(Pstream::nProcs() - 1);
608 int slave = Pstream::firstSlave();
609 slave <= Pstream::lastSlave();
613 IPstream fromSlave(Pstream::scheduled, slave);
614 fromSlave >> slaveMachine >> slavePid;
616 slaveProcs[procI++] = slaveMachine + "." + name(slavePid);
621 OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
622 toMaster << hostName() << pid();
627 if (Pstream::master() && bannerEnabled)
629 Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
630 << "nProcs : " << nProcs << endl;
632 if (parRunControl_.parRun())
634 Info<< "Slaves : " << slaveProcs << nl
635 << "Pstream initialized with:" << nl
636 << " floatTransfer : "
637 << Pstream::floatTransfer << nl
638 << " nProcsSimpleSum : "
639 << Pstream::nProcsSimpleSum() << nl
641 << Pstream::commsTypeNames[Pstream::defaultCommsType()]
646 jobInfo.add("root", rootPath_);
647 jobInfo.add("case", globalCase_);
648 jobInfo.add("nProcs", nProcs);
649 if (slaveProcs.size())
651 jobInfo.add("slaves", slaveProcs);
655 // Switch on signal trapping. We have to wait until after Pstream::init
656 // since this sets up its own ones.
657 sigFpe_.set(bannerEnabled);
658 sigInt_.set(bannerEnabled);
659 sigQuit_.set(bannerEnabled);
660 sigSegv_.set(bannerEnabled);
662 if (Pstream::master() && bannerEnabled)
665 IOobject::writeDivider(Info);
668 // If the macro AppSpecificDictionary is used, one can
669 // modify the application-specific dictionnary using the
670 // command-line parameter -appDict
671 if (appDictName_ != "")
673 optionReadIfPresent("appDict", appDictName_);
678 // * * * * * * * * * * * * * * * * Destructors * * * * * * * * * * * * * * * //
680 Foam::argList::~argList()
686 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
688 void Foam::argList::noBanner()
690 bannerEnabled = false;
694 void Foam::argList::noParallel()
696 validOptions.erase("parallel");
700 void Foam::argList::printUsage() const
703 << "Usage: " << executable_;
707 SLList<string>::iterator iter = validArgs.begin();
708 iter != validArgs.end();
712 Info<< " <" << iter().c_str() << '>';
716 SortableList<Foam::string> sortedValidOptions(validOptions.size());
720 HashTable<string>::iterator iter = validOptions.begin();
721 iter != validOptions.end();
725 OStringStream keyValuePair;
726 keyValuePair << "[-" << iter.key();
730 keyValuePair<< ' ' << iter().c_str();
734 sortedValidOptions[i]= keyValuePair.str();
736 sortedValidOptions.sort();
738 forAll (sortedValidOptions, sI)
739 Info<< " " << sortedValidOptions[sI].c_str();
741 // place help/doc/srcDoc options of the way at the end,
742 // but with an extra space to separate it a little
743 Info<< " [-help] [-doc] [-srcDoc]\n" << endl;
747 void Foam::argList::displayDoc(bool source) const
749 const dictionary& docDict = debug::controlDict().subDict("Documentation");
750 List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
751 List<fileName> docExts(docDict.lookup("doxySourceFileExts"));
753 // for source code: change foo_8C.html to foo_8C_source.html
756 forAll (docExts, extI)
758 docExts[extI].replace(".", "_source.");
765 forAll (docDirs, dirI)
767 forAll (docExts, extI)
769 docFile = docDirs[dirI]/executable_ + docExts[extI];
786 string docBrowser(docDict.lookup("docBrowser"));
787 docBrowser.replaceAll("%f", docFile);
789 Info<< "Show documentation: " << docBrowser.c_str() << endl;
796 << "No documentation found for " << executable_
797 << ", but you can use -help to display the usage\n" << endl;
802 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
806 if (Pstream::master())
808 if (checkArgs && args_.size() - 1 != validArgs.size())
811 << "Wrong number of arguments, expected " << validArgs.size()
812 << " found " << args_.size() - 1 << endl;
818 forAllConstIter(HashTable<string>, options_, iter)
822 !validOptions.found(iter.key())
823 && !validParOptions.found(iter.key())
827 << "Invalid option: -" << iter.key() << endl;
843 bool Foam::argList::checkRootCase() const
845 if (!isDir(rootPath()))
849 << ": cannot open root directory " << rootPath()
855 if (!isDir(path()) && Pstream::master())
857 // Allow slaves on non-existing processor directories, created later
860 << ": cannot open case directory " << path()
870 // ************************************************************************* //