00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "argList.H"
00027 #include <OpenFOAM/OSspecific.H>
00028 #include <OpenFOAM/clock.H>
00029 #include <OpenFOAM/IFstream.H>
00030 #include <OpenFOAM/dictionary.H>
00031 #include <OpenFOAM/Switch.H>
00032 #include <OpenFOAM/IOobject.H>
00033 #include <OpenFOAM/JobInfo.H>
00034 #include <OpenFOAM/labelList.H>
00035 #include <OpenFOAM/ListOps.H>
00036
00037
00038
00039
00040 Foam::SLList<Foam::string> Foam::argList::validArgs;
00041 Foam::HashTable<Foam::string> Foam::argList::validOptions;
00042 Foam::HashTable<Foam::string> Foam::argList::validParOptions;
00043 bool Foam::argList::bannerEnabled(true);
00044
00045
00046 Foam::argList::initValidTables::initValidTables()
00047 {
00048 validOptions.set("case", "dir");
00049 validOptions.set("parallel", "");
00050 validParOptions.set("parallel", "");
00051
00052 Pstream::addValidParOptions(validParOptions);
00053 }
00054
00055
00056 Foam::argList::initValidTables dummyInitValidTables;
00057
00058
00059
00060
00061 bool Foam::argList::regroupArgv(int& argc, char**& argv)
00062 {
00063 int nArgs = 0;
00064 int listDepth = 0;
00065 string tmpString;
00066
00067
00068
00069 for (int argI = 0; argI < argc; argI++)
00070 {
00071 if (strcmp(argv[argI], "(") == 0)
00072 {
00073 listDepth++;
00074 tmpString += "(";
00075 }
00076 else if (strcmp(argv[argI], ")") == 0)
00077 {
00078 if (listDepth)
00079 {
00080 listDepth--;
00081 tmpString += ")";
00082 if (listDepth == 0)
00083 {
00084 args_[nArgs++] = tmpString;
00085 tmpString.clear();
00086 }
00087 }
00088 else
00089 {
00090 args_[nArgs++] = argv[argI];
00091 }
00092 }
00093 else if (listDepth)
00094 {
00095
00096 tmpString += "\"";
00097 tmpString += argv[argI];
00098 tmpString += "\"";
00099 }
00100 else
00101 {
00102 args_[nArgs++] = argv[argI];
00103 }
00104 }
00105
00106 if (tmpString.size())
00107 {
00108 args_[nArgs++] = tmpString;
00109 }
00110
00111 args_.setSize(nArgs);
00112
00113 return nArgs < argc;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 void Foam::argList::getRootCase()
00125 {
00126 fileName casePath;
00127
00128
00129 HashTable<string>::iterator iter = options_.find("case");
00130
00131 if (iter != options_.end())
00132 {
00133 casePath = iter();
00134 casePath.clean();
00135
00136 if (casePath.empty() || casePath == ".")
00137 {
00138
00139 casePath = cwd();
00140 options_.erase("case");
00141 }
00142 else if (casePath[0] != '/' && casePath.name() == "..")
00143 {
00144
00145 casePath = cwd()/casePath;
00146 casePath.clean();
00147 }
00148 }
00149 else
00150 {
00151
00152 casePath = cwd();
00153 }
00154
00155 rootPath_ = casePath.path();
00156 globalCase_ = casePath.name();
00157 case_ = globalCase_;
00158
00159
00160
00161 if (rootPath_[0] == '/')
00162 {
00163
00164 setEnv("FOAM_CASE", rootPath_/globalCase_, true);
00165 setEnv("FOAM_CASENAME", globalCase_, true);
00166 }
00167 else
00168 {
00169
00170 fileName casePath = cwd()/rootPath_/globalCase_;
00171 casePath.clean();
00172
00173 setEnv("FOAM_CASE", casePath, true);
00174 setEnv("FOAM_CASENAME", casePath.name(), true);
00175 }
00176
00177
00178 }
00179
00180
00181 Foam::stringList::subList Foam::argList::additionalArgs() const
00182 {
00183 return stringList::subList(args_, args_.size() - 1, 1);
00184 }
00185
00186
00187
00188
00189 Foam::argList::argList
00190 (
00191 int& argc,
00192 char**& argv,
00193 bool checkArgs,
00194 bool checkOpts
00195 )
00196 :
00197 args_(argc),
00198 options_(argc)
00199 {
00200
00201
00202 for (int argI = 0; argI < argc; argI++)
00203 {
00204 if (argv[argI][0] == '-')
00205 {
00206 const char *optionName = &argv[argI][1];
00207
00208 if (validParOptions.found(optionName))
00209 {
00210 parRunControl_.runPar(argc, argv);
00211 break;
00212 }
00213 }
00214 }
00215
00216
00217
00218 regroupArgv(argc, argv);
00219
00220
00221 args_[0] = fileName(argv[0]);
00222 executable_ = fileName(argv[0]).name();
00223
00224
00225 int nArgs = 1;
00226 string argListString = args_[0];
00227
00228 for (int argI = 1; argI < args_.size(); argI++)
00229 {
00230 argListString += ' ';
00231 argListString += args_[argI];
00232
00233 if (args_[argI][0] == '-')
00234 {
00235 const char *optionName = &args_[argI][1];
00236
00237 if
00238 (
00239 (
00240 validOptions.found(optionName)
00241 && validOptions[optionName] != ""
00242 )
00243 || (
00244 validParOptions.found(optionName)
00245 && validParOptions[optionName] != ""
00246 )
00247 )
00248 {
00249 argI++;
00250 if (argI >= args_.size())
00251 {
00252 FatalError
00253 << "option " << "'-" << optionName << '\''
00254 << " requires an argument"
00255 << exit(FatalError);
00256 }
00257
00258 argListString += ' ';
00259 argListString += args_[argI];
00260 options_.insert(optionName, args_[argI]);
00261 }
00262 else
00263 {
00264 options_.insert(optionName, "");
00265 }
00266 }
00267 else
00268 {
00269 if (nArgs != argI)
00270 {
00271 args_[nArgs] = args_[argI];
00272 }
00273 nArgs++;
00274 }
00275 }
00276
00277 args_.setSize(nArgs);
00278
00279
00280
00281
00282
00283 if
00284 (
00285 options_.found("help")
00286 || options_.found("doc")
00287 || options_.found("srcDoc")
00288 )
00289 {
00290 if (options_.found("help"))
00291 {
00292 printUsage();
00293 }
00294
00295
00296 if (options_.found("srcDoc"))
00297 {
00298 displayDoc(true);
00299 }
00300 else if (options_.found("doc"))
00301 {
00302 displayDoc(false);
00303 }
00304
00305 ::exit(0);
00306 }
00307
00308
00309 if (!check(checkArgs, checkOpts))
00310 {
00311 FatalError.exit();
00312 }
00313
00314
00315 string dateString = clock::date();
00316 string timeString = clock::clockTime();
00317
00318
00319 if (Pstream::master() && bannerEnabled)
00320 {
00321 IOobject::writeBanner(Info, true)
00322 << "Build : " << Foam::FOAMbuild << nl
00323 << "Exec : " << argListString.c_str() << nl
00324 << "Date : " << dateString.c_str() << nl
00325 << "Time : " << timeString.c_str() << nl
00326 << "Host : " << hostName() << nl
00327 << "PID : " << pid() << endl;
00328 }
00329
00330 jobInfo.add("startDate", dateString);
00331 jobInfo.add("startTime", timeString);
00332 jobInfo.add("userName", userName());
00333 jobInfo.add("foamVersion", word(FOAMfullVersion));
00334 jobInfo.add("foamBuild", Foam::FOAMbuild);
00335 jobInfo.add("foamUpstreamVersion", word(FOAMupstreamVersion));
00336 jobInfo.add("code", executable_);
00337 jobInfo.add("argList", argListString);
00338 jobInfo.add("currentDir", cwd());
00339 jobInfo.add("PPID", ppid());
00340 jobInfo.add("PGID", pgid());
00341
00342
00343
00344 int nProcs = 1;
00345
00346
00347 if (parRunControl_.parRun())
00348 {
00349
00350 if (Pstream::master())
00351 {
00352
00353 getRootCase();
00354
00355 IFstream decompDictStream
00356 (
00357 rootPath_/globalCase_/"system/decomposeParDict"
00358 );
00359
00360 if (!decompDictStream.good())
00361 {
00362 FatalError
00363 << "Cannot read "
00364 << decompDictStream.name()
00365 << exit(FatalError);
00366 }
00367
00368 dictionary decompDict(decompDictStream);
00369
00370 label dictNProcs
00371 (
00372 readLabel
00373 (
00374 decompDict.lookup("numberOfSubdomains")
00375 )
00376 );
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 if (dictNProcs > Pstream::nProcs())
00388 {
00389 FatalError
00390 << decompDictStream.name()
00391 << " specifies " << dictNProcs
00392 << " processors but job was started with "
00393 << Pstream::nProcs() << " processors."
00394 << exit(FatalError);
00395 }
00396
00397
00398 if (decompDict.lookupOrDefault<Switch>("distributed", false))
00399 {
00400 fileNameList roots;
00401 decompDict.lookup("roots") >> roots;
00402
00403 if (roots.size() != Pstream::nProcs()-1)
00404 {
00405 FatalError
00406 << "number of entries in decompositionDict::roots"
00407 << " is not equal to the number of slaves "
00408 << Pstream::nProcs()-1
00409 << exit(FatalError);
00410 }
00411
00412
00413 bool hadCaseOpt = options_.found("case");
00414 for
00415 (
00416 int slave=Pstream::firstSlave();
00417 slave<=Pstream::lastSlave();
00418 slave++
00419 )
00420 {
00421 options_.set
00422 (
00423 "case",
00424 fileName(roots[slave-1])/globalCase_
00425 );
00426
00427 OPstream toSlave(Pstream::scheduled, slave);
00428 toSlave << args_ << options_;
00429 }
00430 options_.erase("case");
00431
00432
00433 if (hadCaseOpt)
00434 {
00435 options_.set("case", rootPath_/globalCase_);
00436 }
00437 }
00438 else
00439 {
00440
00441
00442 if (dictNProcs < Pstream::nProcs())
00443 {
00444 label nProcDirs = 0;
00445 while
00446 (
00447 isDir
00448 (
00449 rootPath_/globalCase_/"processor"
00450 + name(++nProcDirs)
00451 )
00452 )
00453 {}
00454
00455 if (nProcDirs != Pstream::nProcs())
00456 {
00457 FatalError
00458 << "number of processor directories = "
00459 << nProcDirs
00460 << " is not equal to the number of processors = "
00461 << Pstream::nProcs()
00462 << exit(FatalError);
00463 }
00464 }
00465
00466
00467 for
00468 (
00469 int slave=Pstream::firstSlave();
00470 slave<=Pstream::lastSlave();
00471 slave++
00472 )
00473 {
00474 OPstream toSlave(Pstream::scheduled, slave);
00475 toSlave << args_ << options_;
00476 }
00477 }
00478 }
00479 else
00480 {
00481
00482 IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
00483 fromMaster >> args_ >> options_;
00484
00485
00486 getRootCase();
00487 }
00488
00489 nProcs = Pstream::nProcs();
00490 case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
00491 }
00492 else
00493 {
00494
00495 getRootCase();
00496 case_ = globalCase_;
00497 }
00498
00499
00500 wordList slaveProcs;
00501
00502
00503 if (parRunControl_.parRun())
00504 {
00505 if (Pstream::master())
00506 {
00507 slaveProcs.setSize(Pstream::nProcs() - 1);
00508 word slaveMachine;
00509 label slavePid;
00510
00511 label procI = 0;
00512 for
00513 (
00514 int slave=Pstream::firstSlave();
00515 slave<=Pstream::lastSlave();
00516 slave++
00517 )
00518 {
00519 IPstream fromSlave(Pstream::scheduled, slave);
00520 fromSlave >> slaveMachine >> slavePid;
00521
00522 slaveProcs[procI++] = slaveMachine + "." + name(slavePid);
00523 }
00524 }
00525 else
00526 {
00527 OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
00528 toMaster << hostName() << pid();
00529 }
00530 }
00531
00532
00533 if (Pstream::master() && bannerEnabled)
00534 {
00535 Info<< "Case : " << (rootPath_/globalCase_).c_str() << nl
00536 << "nProcs : " << nProcs << endl;
00537
00538 if (parRunControl_.parRun())
00539 {
00540 Info<< "Slaves : " << slaveProcs << nl
00541 << "Pstream initialized with:" << nl
00542 << " floatTransfer : " << Pstream::floatTransfer << nl
00543 << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
00544 << " commsType : "
00545 << Pstream::commsTypeNames[Pstream::defaultCommsType]
00546 << endl;
00547 }
00548 }
00549
00550 jobInfo.add("root", rootPath_);
00551 jobInfo.add("case", globalCase_);
00552 jobInfo.add("nProcs", nProcs);
00553 if (slaveProcs.size())
00554 {
00555 jobInfo.add("slaves", slaveProcs);
00556 }
00557 jobInfo.write();
00558
00559
00560
00561 sigFpe_.set(bannerEnabled);
00562 sigInt_.set(bannerEnabled);
00563 sigQuit_.set(bannerEnabled);
00564 sigSegv_.set(bannerEnabled);
00565
00566 if (Pstream::master() && bannerEnabled)
00567 {
00568 Info<< endl;
00569 IOobject::writeDivider(Info);
00570 }
00571 }
00572
00573
00574
00575
00576 Foam::argList::~argList()
00577 {
00578 jobInfo.end();
00579 }
00580
00581
00582
00583
00584 void Foam::argList::noBanner()
00585 {
00586 bannerEnabled = false;
00587 }
00588
00589
00590 void Foam::argList::noParallel()
00591 {
00592 validOptions.erase("parallel");
00593 }
00594
00595
00596 void Foam::argList::printUsage() const
00597 {
00598 Info<< nl
00599 << "Usage: " << executable_;
00600
00601 for
00602 (
00603 SLList<string>::iterator iter = validArgs.begin();
00604 iter != validArgs.end();
00605 ++iter
00606 )
00607 {
00608 Info<< " <" << iter().c_str() << '>';
00609 }
00610
00611 for
00612 (
00613 HashTable<string>::iterator iter = validOptions.begin();
00614 iter != validOptions.end();
00615 ++iter
00616 )
00617 {
00618 Info<< " [-" << iter.key();
00619
00620 if (iter().size())
00621 {
00622 Info<< ' ' << iter().c_str();
00623 }
00624
00625 Info<< ']';
00626 }
00627
00628
00629
00630 Info<< " [-help] [-doc] [-srcDoc]\n" << endl;
00631 }
00632
00633
00634 void Foam::argList::displayDoc(bool source) const
00635 {
00636 const dictionary& docDict = debug::controlDict().subDict("Documentation");
00637
00638 List<fileName> docIndexFiles(docDict.lookup("doxyDocIndices"));
00639
00640 bool found = false;
00641 fileName docFile;
00642
00643 forAll(docIndexFiles,idxI)
00644 {
00645 IFstream indexFile(docIndexFiles[idxI]);
00646
00647 if (!indexFile.good())
00648 {
00649 WarningIn("Foam::argList::displayDoc(bool)")
00650 << "Cannot open documentation index file " << docIndexFiles[idxI]
00651 << endl;
00652 }
00653 else
00654 {
00655
00656 dictionary indexDict(indexFile);
00657 if (indexDict.found("docDir") && indexDict.found("docFiles"))
00658 {
00659 fileName docDir;
00660 dictionary docFiles;
00661
00662 indexDict.lookup("docDir") >> docDir;
00663
00664 docFiles = indexDict.subDict("docFiles");
00665
00666 if (docFiles.found(executable_))
00667 {
00668 found = true;
00669 docFile = docDir / FixedList<fileName,2>( docFiles.lookup(executable_) )[label(source)];
00670 }
00671 }
00672 else
00673 {
00674 WarningIn("Foam::argList::displayDoc(bool)")
00675 << "The file " << docIndexFiles[idxI]
00676 << "does not contain one or both of the entries"
00677 << "\"docDir\" and \"docFiles\"."
00678 << endl;
00679 }
00680 }
00681 }
00682
00683 if (found)
00684 {
00685 string docBrowser(docDict.lookup("docBrowser"));
00686 if (docBrowser != "ECHO")
00687 {
00688 docBrowser.replaceAll("%f", docFile);
00689
00690 Info<< "Show documentation: " << docBrowser.c_str() << endl;
00691
00692 system(docBrowser);
00693 }
00694 else
00695 {
00696 Info<< "Documentation available at: " << docFile << endl;
00697 }
00698 }
00699 else
00700 {
00701 Info<< nl
00702 << "No documentation found for " << executable_
00703 << ", but you can use -help to display the usage\n" << endl;
00704 }
00705 }
00706
00707
00708 bool Foam::argList::check(bool checkArgs, bool checkOpts) const
00709 {
00710 bool ok = true;
00711
00712 if (Pstream::master())
00713 {
00714 if (checkArgs && args_.size() - 1 != validArgs.size())
00715 {
00716 FatalError
00717 << "Wrong number of arguments, expected " << validArgs.size()
00718 << " found " << args_.size() - 1 << endl;
00719 ok = false;
00720 }
00721
00722 if (checkOpts)
00723 {
00724 forAllConstIter(HashTable<string>, options_, iter)
00725 {
00726 if
00727 (
00728 !validOptions.found(iter.key())
00729 && !validParOptions.found(iter.key())
00730 )
00731 {
00732 FatalError
00733 << "Invalid option: -" << iter.key() << endl;
00734 ok = false;
00735 }
00736 }
00737 }
00738
00739 if (!ok)
00740 {
00741 printUsage();
00742 }
00743 }
00744
00745 return ok;
00746 }
00747
00748
00749 bool Foam::argList::checkRootCase() const
00750 {
00751 if (!isDir(rootPath()))
00752 {
00753 FatalError
00754 << executable_
00755 << ": cannot open root directory " << rootPath()
00756 << endl;
00757
00758 return false;
00759 }
00760
00761 if (!isDir(path()) && Pstream::master())
00762 {
00763
00764 FatalError
00765 << executable_
00766 << ": cannot open case directory " << path()
00767 << endl;
00768
00769 return false;
00770 }
00771
00772 return true;
00773 }
00774
00775
00776