1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
28 #include "OSspecific.H"
31 #include "dictionary.H"
35 #include "labelList.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 SLList<string> argList::validArgs;
43 HashTable<string> argList::validOptions;
44 HashTable<string> argList::validParOptions;
48 Foam::argList::initValidTables::initValidTables()
50 validOptions.insert("case", "dir");
51 validOptions.insert("parallel", "");
52 validParOptions.insert("parallel", "");
54 Pstream::addValidParOptions(validParOptions);
58 Foam::argList::initValidTables dummyInitValidTables;
61 // convert argv -> args_
62 // transform sequences with "(" ... ")" into string lists in the process
63 bool Foam::argList::regroupArgv(int& argc, char**& argv)
69 // note: we also re-write directly into args_
70 // and use a second pass to sort out args/options
71 for (int argi=0; argi < argc; argi++)
73 if (strcmp(argv[argi], "(") == 0)
78 else if (strcmp(argv[argi], ")") == 0)
86 args_[nArgs++] = tmpString;
92 args_[nArgs++] = argv[argi];
97 // quote each string element
99 tmpString += argv[argi];
104 args_[nArgs++] = argv[argi];
108 if (tmpString.size())
110 args_[nArgs++] = tmpString;
113 args_.setSize(nArgs);
119 // get rootPath_ / globalCase_ from one of the following forms
122 void Foam::argList::getRootCase()
126 // [-case dir] specified
127 HashTable<string>::iterator iter = options_.find("case");
129 if (iter != options_.end())
132 casePath.removeRepeated('/');
133 casePath.removeTrailing('/');
137 // nothing specified, use the current dir
140 // we could add this back in as '-case'?
141 // options_.insert("case", casePath);
144 rootPath_ = casePath.path();
145 globalCase_ = casePath.name();
150 Foam::stringList::subList Foam::argList::additionalArgs() const
152 return stringList::subList(args_, args_.size() - 1, 1);
156 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
158 Foam::argList::argList
169 // Check if this run is a parallel run by searching for any parallel option
170 // If found call runPar (might filter argv)
171 for (int argi=0; argi<argc; argi++)
173 if (argv[argi][0] == '-')
175 const char *optionName = &argv[argi][1];
177 if (validParOptions.found(optionName))
179 parRunControl_.runPar(argc, argv);
185 // convert argv -> args_ and capture ( ... ) lists
186 // for normal arguments and for options
187 regroupArgv(argc, argv);
189 // Get executable name
190 args_[0] = fileName(argv[0]);
191 executable_ = fileName(argv[0]).name();
193 // Check arguments and options, we already have argv[0]
195 string argListString = args_[0];
197 for (int argi = 1; argi < args_.size(); argi++)
199 argListString += ' ';
200 argListString += args_[argi];
202 if (args_[argi][0] == '-')
204 const char *optionName = &args_[argi][1];
209 validOptions.found(optionName)
210 && validOptions[optionName] != ""
213 validParOptions.found(optionName)
214 && validParOptions[optionName] != ""
219 if (argi >= args_.size())
222 << "option " << "'-" << optionName << '\''
223 << " requires an argument"
227 argListString += ' ';
228 argListString += args_[argi];
229 options_.insert(optionName, args_[argi]);
233 options_.insert(optionName, "");
240 args_[nArgs] = args_[argi];
246 args_.setSize(nArgs);
248 // Help/documentation options:
249 // -help print the usage
250 // -doc display application documentation in browser
251 // -srcDoc display source code in browser
254 options_.found("help")
255 || options_.found("doc")
256 || options_.found("srcDoc")
259 if (options_.found("help"))
264 // only display one or the other
265 if (options_.found("srcDoc"))
269 else if (options_.found("doc"))
277 // Print the usage message and exit if the number of arguments is incorrect
278 if (!check(checkArgs, checkOpts))
284 string dateString = clock::date();
285 string timeString = clock::clockTime();
287 // Print the banner once only for parallel runs
288 if (Pstream::master())
290 IOobject::writeBanner(Info, true);
291 Info<< "Exec : " << argListString.c_str() << nl
292 << "Date : " << dateString.c_str() << nl
293 << "Time : " << timeString.c_str() << nl
294 << "Host : " << hostName() << nl
295 << "PID : " << pid() << endl;
298 jobInfo.add("startDate", dateString);
299 jobInfo.add("startTime", timeString);
300 jobInfo.add("userName", userName());
301 jobInfo.add("foamVersion", word(FOAMversion));
302 jobInfo.add("code", executable_);
303 jobInfo.add("argList", argListString);
304 jobInfo.add("currentDir", cwd());
305 jobInfo.add("PPID", ppid());
306 jobInfo.add("PGID", pgid());
309 // Case is a single processor run unless it is running parallel
312 // If this actually is a parallel run
313 if (parRunControl_.parRun())
316 if (Pstream::master())
320 // establish rootPath_/globalCase_/case_ for master
323 IFstream decompDictStream
325 rootPath_/globalCase_/"system/decomposeParDict"
328 if (!decompDictStream.good())
332 << decompDictStream.name()
336 dictionary decompositionDict(decompDictStream);
338 Switch distributed(false);
342 decompositionDict.readIfPresent("distributed", distributed)
346 decompositionDict.lookup("roots") >> roots;
348 if (roots.size() != Pstream::nProcs()-1)
351 << "number of entries in decompositionDict::roots"
352 << " is not equal to the number of slaves "
353 << Pstream::nProcs()-1
363 decompositionDict.lookup("numberOfSubdomains")
367 // Check number of processors. We have nProcs(number of
368 // actual processes), dictNProcs(wanted number of processes read
369 // from decompositionDict) and nProcDirs(number of processor
370 // directories - n/a when running distributed)
372 // - normal running : nProcs = dictNProcs = nProcDirs
373 // - decomposition to more processors : nProcs = dictNProcs
374 // - decomposition to less processors : nProcs = nProcDirs
375 if (dictNProcs > Pstream::nProcs())
378 << decompDictStream.name()
379 << " specifies " << dictNProcs
380 << " processors but job was started with "
381 << Pstream::nProcs() << " processors."
385 if (!distributed && dictNProcs < Pstream::nProcs())
387 // Possibly going to fewer processors.
388 // Check if all procDirs are there.
394 rootPath_/globalCase_/"processor"
400 if (nProcDirs != Pstream::nProcs())
403 << "number of processor directories = "
405 << " is not equal to the number of processors = "
414 bool hadOptCase = options_.found("case");
416 // Distribute the master's argument list (with new root)
419 int slave=Pstream::firstSlave();
420 slave<=Pstream::lastSlave();
424 options_.erase("case");
428 fileName(roots[slave-1])/globalCase_
431 OPstream toSlave(Pstream::scheduled, slave);
432 toSlave << args_ << options_;
435 options_.erase("case");
437 // restore [-case dir]
440 options_.insert("case", rootPath_/globalCase_);
445 // Distribute the master's argument list (unaltered)
448 int slave=Pstream::firstSlave();
449 slave<=Pstream::lastSlave();
453 OPstream toSlave(Pstream::scheduled, slave);
454 toSlave << args_ << options_;
460 // Collect the master's argument list
461 IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
462 fromMaster >> args_ >> options_;
464 // establish rootPath_/globalCase_/case_ for slave
468 nProcs = Pstream::nProcs();
469 case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
473 // establish rootPath_/globalCase_/case_
482 // collect slave machine/pid
483 if (parRunControl_.parRun())
485 if (Pstream::master())
487 slaveProcs.setSize(Pstream::nProcs() - 1);
494 int slave=Pstream::firstSlave();
495 slave<=Pstream::lastSlave();
499 IPstream fromSlave(Pstream::scheduled, slave);
500 fromSlave >> slaveMachine >> slavePid;
502 slaveProcs[procI++] = slaveMachine + "." + name(slavePid);
507 OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
508 toMaster << hostName() << pid();
513 if (Pstream::master())
515 Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
516 << "nProcs : " << nProcs << endl;
519 if (parRunControl_.parRun() && Pstream::master())
521 Info<< "Slaves : " << slaveProcs << nl
522 << "Pstream initialized with:" << nl
523 << " floatTransfer : " << Pstream::floatTransfer << nl
524 << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
526 << Pstream::commsTypeNames[Pstream::defaultCommsType]
530 jobInfo.add("root", rootPath_);
531 jobInfo.add("case", globalCase_);
532 jobInfo.add("nProcs", nProcs);
533 if (slaveProcs.size())
535 jobInfo.add("slaves", slaveProcs);
539 // Set the case as an environment variable
540 setEnv("FOAM_CASE", rootPath_/globalCase_, true);
542 // Switch on signal trapping. We have to wait until after Pstream::init
543 // since this sets up its own ones.
549 if (Pstream::master())
552 IOobject::writeDivider(Info);
557 // * * * * * * * * * * * * * * * * Destructors * * * * * * * * * * * * * * * //
559 Foam::argList::~argList()
565 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
567 void Foam::argList::noParallel()
569 validOptions.erase("parallel");
573 void Foam::argList::printUsage() const
576 << "Usage: " << executable_;
580 SLList<string>::iterator iter = validArgs.begin();
581 iter != validArgs.end();
585 Info<< " <" << iter().c_str() << '>';
590 HashTable<string>::iterator iter = validOptions.begin();
591 iter != validOptions.end();
595 Info<< " [-" << iter.key();
599 Info<< ' ' << iter().c_str();
605 // place help/doc/srcDoc options of the way at the end,
606 // but with an extra space to separate it a little
607 Info<< " [-help] [-doc] [-srcDoc]\n" << endl;
611 void Foam::argList::displayDoc(bool source) const
613 const dictionary& docDict = debug::controlDict().subDict("Documentation");
614 List<fileName> docDirs(docDict.lookup("doxyDocDirs"));
615 List<fileName> docExts(docDict.lookup("doxySourceFileExts"));
617 // for source code: change foo_8C.html to foo_8C-source.html
620 forAll(docExts, extI)
622 docExts[extI].replace(".", "-source.");
629 forAll(docDirs, dirI)
631 forAll(docExts, extI)
633 docFile = docDirs[dirI]/executable_ + docExts[extI];
650 string docBrowser(docDict.lookup("docBrowser"));
651 docBrowser.replaceAll("%f", docFile);
653 Info<< "Show documentation: " << docBrowser.c_str() << endl;
660 << "No documentation found for " << executable_
661 << ", but you can use -help to display the usage\n" << endl;
666 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
670 if (Pstream::master())
672 if (checkArgs && args_.size() - 1 != validArgs.size())
675 << "Wrong number of arguments, expected " << validArgs.size()
676 << " found " << args_.size() - 1 << endl;
682 forAllConstIter(HashTable<string>, options_, iter)
686 !validOptions.found(iter.key())
687 && !validParOptions.found(iter.key())
691 << "Invalid option: -" << iter.key() << endl;
707 bool Foam::argList::checkRootCase() const
709 if (!dir(rootPath()))
713 << ": cannot open root directory " << rootPath()
719 if (!dir(path()) && Pstream::master())
721 // Allow slaves on non-existing processor directories, created later
724 << ": cannot open case directory " << path()
734 // ************************************************************************* //