ENH: support command-line specification of MPI threads (#2791)

- MPI_THREAD_MULTIPLE is usually undesirable for performance reasons,
  but in some cases may be necessary if a linked library expects it.
  Provide a '-mpi-threads' option to explicitly request it.

ENH: consolidate some looping logic within argList
This commit is contained in:
Mark Olesen 2023-06-15 11:23:31 +02:00
parent b2217d5e6b
commit 4412566c58
14 changed files with 366 additions and 233 deletions

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -124,6 +124,9 @@ int main(int argc, char *argv[])
argList::addDryRunOption("Just for testing"); argList::addDryRunOption("Just for testing");
argList::addVerboseOption("Increase verbosity"); argList::addVerboseOption("Increase verbosity");
// Check -verbose before initialisation
UPstream::debug = argList::verbose(argc, argv);
#include "setRootCase.H" #include "setRootCase.H"
Pout<< "command-line (" Pout<< "command-line ("

View File

@ -42,6 +42,7 @@ Description
using namespace Foam; using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void printInfo(const label comm) void printInfo(const label comm)
{ {
@ -65,20 +66,10 @@ int main(int argc, char *argv[])
{ {
argList::noBanner(); argList::noBanner();
argList::noCheckProcessorDirectories(); argList::noCheckProcessorDirectories();
argList::addBoolOption("verbose", "Set debug level"); argList::addVerboseOption("Set UPstream::debug level");
// Capture manually. We need values before proper startup
int nVerbose = 0;
for (int argi = 1; argi < argc; ++argi)
{
if (strcmp(argv[argi], "-verbose") == 0)
{
++nVerbose;
}
}
UPstream::debug = nVerbose;
// Check -verbose before initialisation
UPstream::debug = argList::verbose(argc, argv);
#include "setRootCase.H" #include "setRootCase.H"

View File

@ -44,6 +44,8 @@ Description
using namespace Foam; using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void rankInfo(const label comm) void rankInfo(const label comm)
{ {
const int ranki = UPstream::myProcNo(comm); const int ranki = UPstream::myProcNo(comm);
@ -63,7 +65,7 @@ int main(int argc, char *argv[])
{ {
argList::noBanner(); argList::noBanner();
argList::noCheckProcessorDirectories(); argList::noCheckProcessorDirectories();
argList::addBoolOption("verbose", "Set debug level"); argList::addVerboseOption("Set UPstream::debug level");
argList::addBoolOption("info", "information"); argList::addBoolOption("info", "information");
argList::addBoolOption("print-tree", "Report tree(s) as graph"); argList::addBoolOption("print-tree", "Report tree(s) as graph");
argList::addBoolOption("comm-split", "Test simple comm split"); argList::addBoolOption("comm-split", "Test simple comm split");
@ -71,17 +73,8 @@ int main(int argc, char *argv[])
argList::addBoolOption("host-comm", "Test Pstream host-comm"); argList::addBoolOption("host-comm", "Test Pstream host-comm");
argList::addBoolOption("host-broadcast", "Test host-base broadcasts"); argList::addBoolOption("host-broadcast", "Test host-base broadcasts");
// Capture manually. We need values before proper startup // Check -verbose before initialisation
int nVerbose = 0; UPstream::debug = argList::verbose(argc, argv);
for (int argi = 1; argi < argc; ++argi)
{
if (strcmp(argv[argi], "-verbose") == 0)
{
++nVerbose;
}
}
UPstream::debug = nVerbose;
#include "setRootCase.H" #include "setRootCase.H"

View File

@ -44,6 +44,7 @@ Description
using namespace Foam; using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
bool startMPI() bool startMPI()
{ {
@ -121,19 +122,10 @@ int main(int argc, char *argv[])
{ {
argList::noBanner(); argList::noBanner();
argList::noCheckProcessorDirectories(); argList::noCheckProcessorDirectories();
argList::addBoolOption("verbose", "Set debug level"); argList::addVerboseOption("Set UPstream::debug level");
// Need to capture manually, since we need values before proper startup // Check -verbose before initialisation
int nVerbose = 0; UPstream::debug = argList::verbose(argc, argv);
for (int argi = 1; argi < argc; ++argi)
{
if (strcmp(argv[argi], "-verbose") == 0)
{
++nVerbose;
}
}
UPstream::debug = nVerbose;
startMPI(); startMPI();

View File

@ -43,24 +43,15 @@ using namespace Foam;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
argList::noFunctionObjects(); argList::noFunctionObjects();
argList::addBoolOption("verbose", "Set debug level"); argList::addVerboseOption("Set UPstream::debug level");
argList::addBoolOption("comm-graph", "Test simple graph communicator"); argList::addBoolOption("comm-graph", "Test simple graph communicator");
argList::addNote argList::addNote
( (
"Create graph of OpenFOAM mesh connections" "Create graph of OpenFOAM mesh connections"
); );
// Capture manually. We need values before proper startup // Check -verbose before initialisation
int nVerbose = 0; UPstream::debug = argList::verbose(argc, argv);
for (int argi = 1; argi < argc; ++argi)
{
if (strcmp(argv[argi], "-verbose") == 0)
{
++nVerbose;
}
}
UPstream::debug = nVerbose;
#include "setRootCase.H" #include "setRootCase.H"

View File

@ -264,7 +264,7 @@ int main(int argc, char *argv[])
// enable noConstant by switching // enable noConstant by switching
if (!args.found("noConstant")) if (!args.found("noConstant"))
{ {
args.setOption("constant", ""); args.setOption("constant");
} }
else else
{ {

View File

@ -402,7 +402,6 @@ int main(int argc, char *argv[])
timeSelector::addOptions(); timeSelector::addOptions();
argList::addOptionCompat("dry-run", {"test", 1806});
argList::addDryRunOption argList::addDryRunOption
( (
"Test only do not change any files" "Test only do not change any files"
@ -425,7 +424,7 @@ int main(int argc, char *argv[])
instantList timeDirs = timeSelector::select0(runTime, args); instantList timeDirs = timeSelector::select0(runTime, args);
const bool dryrun = args.found("dry-run"); const bool dryrun = args.dryRun();
if (dryrun) if (dryrun)
{ {
Info<< "-dry-run option: no changes made" << nl << endl; Info<< "-dry-run option: no changes made" << nl << endl;

View File

@ -166,10 +166,13 @@ void Foam::Time::readDict()
} }
controlDict_.watchIndices().clear(); controlDict_.watchIndices().clear();
// The new handler, create with some verbosity // Reporting verbosity corresponding to detail level
const bool verbose = (::Foam::infoDetailLevel > 0);
// The new handler
refPtr<fileOperation> newHandler refPtr<fileOperation> newHandler
( (
fileOperation::New(fileHandlerName, true) fileOperation::New(fileHandlerName, verbose)
); );
// Install the new handler // Install the new handler
@ -206,6 +209,9 @@ void Foam::Time::readDict()
IStringStream dummyIs(""); IStringStream dummyIs("");
// Reporting verbosity corresponding to detail level
const bool verbose = (::Foam::infoDetailLevel > 0);
forAllConstIters(objs, iter) forAllConstIters(objs, iter)
{ {
const List<simpleRegIOobject*>& objects = *iter; const List<simpleRegIOobject*>& objects = *iter;
@ -214,7 +220,7 @@ void Foam::Time::readDict()
{ {
obj->readData(dummyIs); obj->readData(dummyIs);
if (Foam::infoDetailLevel > 0) if (verbose)
{ {
Info<< " "; Info<< " ";
obj->writeData(Info); obj->writeData(Info);

View File

@ -54,6 +54,7 @@ License
bool Foam::argList::argsMandatory_ = true; bool Foam::argList::argsMandatory_ = true;
bool Foam::argList::checkProcessorDirectories_ = true; bool Foam::argList::checkProcessorDirectories_ = true;
bool Foam::argList::parallelThreads_ = false;
Foam::SLList<Foam::string> Foam::argList::validArgs; Foam::SLList<Foam::string> Foam::argList::validArgs;
Foam::HashSet<Foam::string> Foam::argList::advancedOptions; Foam::HashSet<Foam::string> Foam::argList::advancedOptions;
@ -122,6 +123,14 @@ Foam::argList::initValidTables::initValidTables()
argList::addBoolOption("parallel", "Run in parallel"); argList::addBoolOption("parallel", "Run in parallel");
validParOptions.set("parallel", ""); validParOptions.set("parallel", "");
argList::addBoolOption
(
"mpi-threads",
"Request use of MPI threads",
true // advanced option
);
argList::addOption argList::addOption
( (
"roots", "roots",
@ -401,7 +410,7 @@ void Foam::argList::addOption
void Foam::argList::setAdvanced(const word& optName, bool advanced) void Foam::argList::setAdvanced(const word& optName, bool advanced)
{ {
if (advanced && validOptions.found(optName)) if (advanced && validOptions.contains(optName))
{ {
advancedOptions.set(optName); advancedOptions.set(optName);
} }
@ -504,7 +513,13 @@ void Foam::argList::addDryRunOption
bool advanced bool advanced
) )
{ {
argList::addBoolOption("dry-run", usage, advanced); const word optName("dry-run", false);
argList::addBoolOption(optName, usage, advanced);
if (!advanced)
{
advancedOptions.erase(optName); // Avoid 'stickiness'
}
} }
@ -514,13 +529,24 @@ void Foam::argList::addVerboseOption
bool advanced bool advanced
) )
{ {
const word optName("verbose", false);
if (usage.empty()) if (usage.empty())
{ {
argList::addBoolOption("verbose", "Additional verbosity", advanced); argList::addBoolOption
(
optName,
"Additional verbosity (can be used multiple times)",
advanced
);
} }
else else
{ {
argList::addBoolOption("verbose", usage, advanced); argList::addBoolOption(optName, usage, advanced);
}
if (!advanced)
{
advancedOptions.erase(optName); // Avoid 'stickiness'
} }
} }
@ -569,10 +595,17 @@ void Foam::argList::noParallel()
removeOption("decomposeParDict"); removeOption("decomposeParDict");
removeOption("hostRoots"); removeOption("hostRoots");
removeOption("world"); removeOption("world");
removeOption("mpi-threads");
validParOptions.clear(); validParOptions.clear();
} }
void Foam::argList::parallelThreads_on()
{
parallelThreads_ = true;
}
void Foam::argList::noCheckProcessorDirectories() void Foam::argList::noCheckProcessorDirectories()
{ {
checkProcessorDirectories_ = false; checkProcessorDirectories_ = false;
@ -581,18 +614,39 @@ void Foam::argList::noCheckProcessorDirectories()
bool Foam::argList::postProcess(int argc, char *argv[]) bool Foam::argList::postProcess(int argc, char *argv[])
{ {
for (int i=1; i<argc; ++i) for (int argi = 1; argi < argc; ++argi)
{ {
if (argv[i] == '-' + postProcessOptionName) const char *optName = argv[argi];
if (optName[0] == '-')
{
++optName; // Looks like an option, skip leading '-'
if (optName == postProcessOptionName)
{ {
return true; return true;
} }
} }
}
return false; return false;
} }
int Foam::argList::verbose(int argc, char *argv[])
{
int num = 0;
for (int argi = 1; argi < argc; ++argi)
{
if (strcmp(argv[argi], "-verbose") == 0)
{
++num;
}
}
return num;
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::word Foam::argList::envExecutable() Foam::word Foam::argList::envExecutable()
@ -694,6 +748,8 @@ int Foam::argList::optionIgnore(const word& optName)
} }
} }
// TBD: could ignore -verbose, -dry-run etc if they are not active...
return 0; // Do not skip return 0; // Do not skip
} }
@ -711,15 +767,19 @@ bool Foam::argList::regroupArgv(int& argc, char**& argv)
args_[0] = fileName(argv[0]); args_[0] = fileName(argv[0]);
for (int argi = 1; argi < argc; ++argi) for (int argi = 1; argi < argc; ++argi)
{ {
if (strcmp(argv[argi], "(") == 0) const char *optName = argv[argi];
if (optName[0] == '(' && optName[1] == '\0')
{ {
// Begin list
++depth; ++depth;
group += '('; group += '(';
} }
else if (strcmp(argv[argi], ")") == 0) else if (optName[0] == ')' && optName[1] == '\0')
{ {
if (depth) if (depth)
{ {
// End list
--depth; --depth;
group += ')'; group += ')';
if (!depth) if (!depth)
@ -730,6 +790,7 @@ bool Foam::argList::regroupArgv(int& argc, char**& argv)
} }
else else
{ {
// A stray ')' - likely never happens
args_[nArgs++] = argv[argi]; args_[nArgs++] = argv[argi];
} }
} }
@ -740,12 +801,11 @@ bool Foam::argList::regroupArgv(int& argc, char**& argv)
group += argv[argi]; group += argv[argi];
group += '"'; group += '"';
} }
else if (argv[argi][0] == '-') else if (optName[0] == '-')
{ {
// Appears to be an option ++optName; // Looks like an option, skip leading '-'
const char *optName = &argv[argi][1];
if (validOptions.found(optName)) if (validOptions.contains(optName))
{ {
// Known option name // Known option name
args_[nArgs++] = argv[argi]; args_[nArgs++] = argv[argi];
@ -848,59 +908,117 @@ Foam::argList::argList
bool initialise bool initialise
) )
: :
runControl_(),
args_(argc), args_(argc),
options_(argc), options_(argc),
libs_() libs_()
{ {
// Check for -fileHandler, which requires an argument. // Pre-scan for some options needed for initial setup:
word handlerType; // -fileHandler (takes an argument)
for (int argi = argc-2; argi > 0; --argi) // -mpi-threads (bool option)
{ //
if (argv[argi][0] == '-') // Also handle -dry-run and -verbose counting
{ // (it is left to the application to decide what to do with them).
const char *optName = &argv[argi][1]; // Detect any parallel run options
if (strcmp(optName, "fileHandler") == 0) word fileHandlerName;
if (parallelThreads_)
{ {
handlerType = argv[argi+1]; // Default -mpi-threads configured statically from application
break; runControl_.threads(true);
}
}
}
if (handlerType.empty())
{
handlerType = Foam::getEnv("FOAM_FILEHANDLER");
if (handlerType.empty())
{
handlerType = fileOperation::defaultFileHandler;
}
} }
// Detect any parallel options
const bool needsThread = fileOperations::fileOperationInitialise::New
(
handlerType,
argc,
argv
)().needsThreading();
// Check if this run is a parallel run by searching for any parallel option
// If found call runPar which might filter argv
for (int argi = 1; argi < argc; ++argi) for (int argi = 1; argi < argc; ++argi)
{ {
if (argv[argi][0] == '-') const char *optName = argv[argi];
{
const char *optName = &argv[argi][1];
if (validParOptions.found(optName)) if (optName[0] == '-')
{ {
runControl_.runPar(argc, argv, needsThread); ++optName; // Looks like an option, skip leading '-'
break; bool emitErrorMessage = false;
if (strcmp(optName, "dry-run") == 0)
{
runControl_.incrDryRun();
}
else if (strcmp(optName, "verbose") == 0)
{
runControl_.incrVerbose();
}
else if (strcmp(optName, "mpi-threads") == 0)
{
runControl_.threads(true);
}
else if (strcmp(optName, "fileHandler") == 0)
{
// Requires a parameter
if (argi < argc-1)
{
++argi;
fileHandlerName = argv[argi];
}
else
{
emitErrorMessage = true;
}
}
else if (validParOptions.contains(optName))
{
// Contains a parallel run option
runControl_.parRun(true);
}
if (emitErrorMessage)
{
// Missing argument: emit message but not exit or
// FatalError since Pstream etc are not yet initialised
Info<< nl
<< "Error: option '-" << optName
<< "' requires an argument" << nl << nl;
//NO: UPstream::exit(1); // works for serial and parallel
} }
} }
} }
// No -fileHandler specifed, get from environment or use default
if (fileHandlerName.empty())
{
fileHandlerName = Foam::getEnv("FOAM_FILEHANDLER");
if (fileHandlerName.empty())
{
fileHandlerName = fileOperation::defaultFileHandler;
}
}
// Parse out any additional fileHandler-specific options
// (may alter argv list). Recover its threading requirements
{
auto fileOperationInit = fileOperations::fileOperationInitialise::New
(
fileHandlerName,
argc,
argv
);
if (fileOperationInit && fileOperationInit->needsThreading())
{
runControl_.threads(true);
}
}
// Parallel job options detected?
// - start parallel run (possibly filters argv as a side-effect)
if (runControl_.parRun())
{
runControl_.runPar(argc, argv);
}
// ------------------------------------------------------------------------
// Convert argv -> args_ and capture ( ... ) lists // Convert argv -> args_ and capture ( ... ) lists
regroupArgv(argc, argv); regroupArgv(argc, argv);
commandLine_ += args_[0]; commandLine_ += args_[0];
@ -908,9 +1026,6 @@ Foam::argList::argList
// Set executable name immediately - useful when emitting errors. // Set executable name immediately - useful when emitting errors.
executable_ = fileName(args_[0]).name(); executable_ = fileName(args_[0]).name();
// Count -dry-run and -verbose switches
int numDryRun = 0, numVerbose = 0;
// Check arguments and options, argv[0] was already handled // Check arguments and options, argv[0] was already handled
int nArgs = 1; int nArgs = 1;
for (int argi = 1; argi < args_.size(); ++argi) for (int argi = 1; argi < args_.size(); ++argi)
@ -918,9 +1033,11 @@ Foam::argList::argList
commandLine_ += ' '; commandLine_ += ' ';
commandLine_ += args_[argi]; commandLine_ += args_[argi];
if (args_[argi][0] == '-') const char *optName = args_[argi].data();
if (optName[0] == '-')
{ {
const char *optName = &args_[argi][1]; ++optName; // Looks like an option, skip leading '-'
if (!*optName) if (!*optName)
{ {
@ -949,7 +1066,7 @@ Foam::argList::argList
if (wantArg) if (wantArg)
{ {
// Known option and expects a parameter // Option expects a parameter
// - get it or emit a FatalError. // - get it or emit a FatalError.
++argi; ++argi;
@ -1019,18 +1136,11 @@ Foam::argList::argList
options_.insert(optName, ""); options_.insert(optName, "");
// Special increment handling for some known flags // // Special increment handling for some known flags
if (wantArg.good()) // if (wantArg.good())
{ // {
if (strcmp(optName, "dry-run") == 0) // ...
{ // }
++numDryRun;
}
else if (strcmp(optName, "verbose") == 0)
{
++numVerbose;
}
}
} }
} }
else else
@ -1043,10 +1153,6 @@ Foam::argList::argList
} }
} }
// Commit number of -dry-run and -verbose flag occurrences
runControl_.dryRun(numDryRun);
runControl_.verbose(numVerbose);
args_.resize(nArgs); args_.resize(nArgs);
parse(checkArgs, checkOpts, initialise); parse(checkArgs, checkOpts, initialise);
@ -1093,42 +1199,42 @@ void Foam::argList::parse
bool quickExit = false; bool quickExit = false;
// Display either application or source documentation, not both // Display either application or source documentation, not both
if (options_.found("doc")) if (options_.contains("doc"))
{ {
displayDoc(false); displayDoc(false);
quickExit = true; quickExit = true;
} }
else if (options_.found("doc-source")) else if (options_.contains("doc-source"))
{ {
displayDoc(true); displayDoc(true);
quickExit = true; quickExit = true;
} }
// Display either short or full help, not both // Display either short or full help, not both
if (options_.found("help-full")) if (options_.contains("help-full"))
{ {
printUsage(true); printUsage(true);
quickExit = true; quickExit = true;
} }
else if (options_.found("help-notes")) else if (options_.contains("help-notes"))
{ {
printNotes(); printNotes();
Info<< nl; Info<< nl;
quickExit = true; quickExit = true;
} }
else if (options_.found("help")) else if (options_.contains("help"))
{ {
printUsage(false); printUsage(false);
quickExit = true; quickExit = true;
} }
else if (options_.found("help-man")) else if (options_.contains("help-man"))
{ {
printMan(); printMan();
quickExit = true; quickExit = true;
} }
// Allow independent display of compatibility information // Allow independent display of compatibility information
if (options_.found("help-compat")) if (options_.contains("help-compat"))
{ {
printCompat(); printCompat();
quickExit = true; quickExit = true;
@ -1221,19 +1327,19 @@ void Foam::argList::parse
// 5. '-fileHandler' commmand-line option // 5. '-fileHandler' commmand-line option
{ {
word handlerType word fileHandlerName
( (
options_.lookup("fileHandler", Foam::getEnv("FOAM_FILEHANDLER")) options_.lookup("fileHandler", Foam::getEnv("FOAM_FILEHANDLER"))
); );
if (handlerType.empty()) if (fileHandlerName.empty())
{ {
handlerType = fileOperation::defaultFileHandler; fileHandlerName = fileOperation::defaultFileHandler;
} }
(void) fileOperation::fileHandler (void) fileOperation::fileHandler
( (
fileOperation::New(handlerType, bannerEnabled()) fileOperation::New(fileHandlerName, bannerEnabled())
); );
} }
@ -1346,7 +1452,7 @@ void Foam::argList::parse
dictNProcs = roots.size()+1; dictNProcs = roots.size()+1;
} }
} }
else if (options_.found("hostRoots")) else if (options_.contains("hostRoots"))
{ {
source = "-hostRoots"; source = "-hostRoots";
runControl_.distributed(true); runControl_.distributed(true);
@ -1546,7 +1652,7 @@ void Foam::argList::parse
} }
// Distribute the master's argument list (with new root) // Distribute the master's argument list (with new root)
const bool hadCaseOpt = options_.found("case"); const bool hadCaseOpt = options_.contains("case");
for (const int subproci : Pstream::subProcs()) for (const int subproci : Pstream::subProcs())
{ {
options_.set("case", roots[subproci-1]/globalCase_); options_.set("case", roots[subproci-1]/globalCase_);
@ -1841,15 +1947,15 @@ Foam::argList::~argList()
bool Foam::argList::allowFunctionObjects() const bool Foam::argList::allowFunctionObjects() const
{ {
if (validOptions.found("withFunctionObjects")) if (validOptions.contains("withFunctionObjects"))
{ {
// '-withFunctionObjects' is available and explicitly enabled // '-withFunctionObjects' is available and explicitly enabled
return options_.found("withFunctionObjects"); return options_.contains("withFunctionObjects");
} }
else if (validOptions.found("noFunctionObjects")) else if (validOptions.contains("noFunctionObjects"))
{ {
// '-noFunctionObjects' is available and not explicitly disabled // '-noFunctionObjects' is available and not explicitly disabled
return !options_.found("noFunctionObjects"); return !options_.contains("noFunctionObjects");
} }
// Disallow functions if there is no way to enable/disable them // Disallow functions if there is no way to enable/disable them
@ -1859,7 +1965,7 @@ bool Foam::argList::allowFunctionObjects() const
bool Foam::argList::allowLibs() const bool Foam::argList::allowLibs() const
{ {
return !options_.found("no-libs"); return !options_.contains("no-libs");
} }
@ -1867,32 +1973,29 @@ bool Foam::argList::allowLibs() const
Foam::label Foam::argList::count(const UList<word>& optionNames) const Foam::label Foam::argList::count(const UList<word>& optionNames) const
{ {
label n = 0; label num = 0;
for (const word& optName : optionNames) for (const word& optName : optionNames)
{ {
if (options_.found(optName)) if (options_.contains(optName))
{ {
++n; ++num;
} }
} }
return n; return num;
} }
Foam::label Foam::argList::count Foam::label Foam::argList::count(std::initializer_list<word> optionNames) const
(
std::initializer_list<word> optionNames
) const
{ {
label n = 0; label num = 0;
for (const word& optName : optionNames) for (const word& optName : optionNames)
{ {
if (options_.found(optName)) if (options_.contains(optName))
{ {
++n; ++num;
} }
} }
return n; return num;
} }
@ -1912,7 +2015,9 @@ bool Foam::argList::setOption(const word& optName, const string& param)
return false; return false;
} }
if (options_.found(optName) ? (options_[optName] != param) : true) const auto optIter = options_.cfind(optName);
if (!optIter.good() || (optIter.val() != param))
{ {
options_.set(optName, param); options_.set(optName, param);
return true; return true;
@ -1930,7 +2035,6 @@ bool Foam::argList::unsetOption(const word& optName)
optName == "case" optName == "case"
|| optName == "parallel" || optName == "parallel"
|| optName == "roots" || optName == "roots"
|| optName == "hostRoots"
) )
{ {
FatalErrorInFunction FatalErrorInFunction
@ -2040,8 +2144,8 @@ bool Foam::argList::check(bool checkArgs, bool checkOpts) const
const word& optName = iter.key(); const word& optName = iter.key();
if if
( (
!validOptions.found(optName) !validOptions.contains(optName)
&& !validParOptions.found(optName) && !validParOptions.contains(optName)
) )
{ {
FatalError FatalError

View File

@ -124,12 +124,15 @@ class argList
{ {
// Private Data // Private Data
//- Track if command arguments are mandatory/optional //- Command arguments are mandatory (default) or optional
static bool argsMandatory_; static bool argsMandatory_;
//- Track enabled/disabled checking of processor directories state //- Check presence of processor directories (default: on)
static bool checkProcessorDirectories_; static bool checkProcessorDirectories_;
//- MPI threads are desired for the application (default: off)
static bool parallelThreads_;
//- Switch on/off parallel mode, dry-run etc. //- Switch on/off parallel mode, dry-run etc.
// Construct first so destructor is done last. // Construct first so destructor is done last.
ParRunControl runControl_; ParRunControl runControl_;
@ -645,11 +648,11 @@ public:
//- Remove the parallel options //- Remove the parallel options
static void noParallel(); static void noParallel();
//- Remove checking of processor directories //- Disable checking of processor directories
static void noCheckProcessorDirectories(); static void noCheckProcessorDirectories();
//- Return true if the post-processing option is specified //- MPI threads are desired for the application
static bool postProcess(int argc, char *argv[]); static void parallelThreads_on();
//- Set option directly (use with caution) //- Set option directly (use with caution)
// An option with an empty param is a bool option. // An option with an empty param is a bool option.
@ -664,6 +667,15 @@ public:
bool unsetOption(const word& optName); bool unsetOption(const word& optName);
// Helpers
//- True if the post-processing option is found in the \c argv list
static bool postProcess(int argc, char *argv[]);
//- The number of times -verbose is found in the \c argv list
static int verbose(int argc, char *argv[]);
// Print // Print
//- Print option compatibility //- Print option compatibility

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd. Copyright (C) 2018-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -102,7 +102,7 @@ static void printManOption(const word& optName)
argList::optionUsage.lookup(optName, string::null) argList::optionUsage.lookup(optName, string::null)
); );
if (argList::validParOptions.found(optName)) if (argList::validParOptions.contains(optName))
{ {
Info<< "\\fB[Parallel option]\\fR" << nl; Info<< "\\fB[Parallel option]\\fR" << nl;
} }
@ -314,7 +314,7 @@ void Foam::argList::printMan() const
for (const word& optName : validOptions.sortedToc()) for (const word& optName : validOptions.sortedToc())
{ {
// Normal (non-advanced) options // Normal (non-advanced) options
if (!advancedOptions.found(optName)) if (!advancedOptions.contains(optName))
{ {
printManOption(optName); printManOption(optName);
} }
@ -333,7 +333,7 @@ void Foam::argList::printMan() const
for (const word& optName : validOptions.sortedToc()) for (const word& optName : validOptions.sortedToc())
{ {
// Advanced options // Advanced options
if (advancedOptions.found(optName)) if (advancedOptions.contains(optName))
{ {
printManOption(optName); printManOption(optName);
} }
@ -418,7 +418,7 @@ void Foam::argList::printUsage(bool full) const
for (const word& optName : validOptions.sortedToc()) for (const word& optName : validOptions.sortedToc())
{ {
// Suppress advanced options for regular -help. // Suppress advanced options for regular -help.
if (full || !advancedOptions.found(optName)) if (full || !advancedOptions.contains(optName))
{ {
printOption(optName); printOption(optName);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -37,7 +37,7 @@ inline void Foam::argList::readList(ITstream& is, List<T>& list)
{ {
// Single token - treat like List with one entry // Single token - treat like List with one entry
list.resize(1); list.resize(1);
is >> list.first(); is >> list.front();
} }
else else
{ {
@ -177,7 +177,7 @@ Foam::argList::options() noexcept
inline bool Foam::argList::found(const word& optName) const inline bool Foam::argList::found(const word& optName) const
{ {
return options_.found(optName); return options_.contains(optName);
} }
@ -309,7 +309,7 @@ inline T Foam::argList::getOrDefault
const T& deflt const T& deflt
) const ) const
{ {
if (found(optName)) if (options_.contains(optName))
{ {
return get<T>(optName); return get<T>(optName);
} }
@ -325,7 +325,7 @@ inline bool Foam::argList::readIfPresent
T& val T& val
) const ) const
{ {
if (found(optName)) if (options_.contains(optName))
{ {
val = get<T>(optName); val = get<T>(optName);
return true; return true;
@ -376,7 +376,7 @@ inline Foam::List<T> Foam::argList::getList
{ {
List<T> list; List<T> list;
if (mandatory || found(optName)) if (mandatory || options_.contains(optName))
{ {
ITstream is(options_[optName]); ITstream is(options_[optName]);
@ -396,7 +396,7 @@ inline bool Foam::argList::readListIfPresent
List<T>& list List<T>& list
) const ) const
{ {
if (found(optName)) if (options_.contains(optName))
{ {
ITstream is(options_[optName]); ITstream is(options_[optName]);

View File

@ -37,10 +37,10 @@ Note
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef argListRunControl_H #ifndef Foam_argListRunControl_H
#define argListRunControl_H #define Foam_argListRunControl_H
#include "Pstream.H" #include "UPstream.H"
#include "IOstreams.H" #include "IOstreams.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -54,22 +54,39 @@ namespace Foam
class ParRunControl class ParRunControl
{ {
// Private Data
//- The dry-run level
int dryRun_; int dryRun_;
//- The verbosity level
int verbose_; int verbose_;
//- True if this is (or will be) a parallel run
bool parallel_; bool parallel_;
//- Uses distributed roots
bool distributed_; bool distributed_;
//- MPI threads are desired
bool needsThread_;
public: public:
// Constructors
//- Default construct //- Default construct
ParRunControl() ParRunControl() noexcept
: :
dryRun_(0), dryRun_(0),
verbose_(0), verbose_(0),
parallel_(false), parallel_(false),
distributed_(false) distributed_(false),
needsThread_(false)
{} {}
//- Destructor. Shutdown (finalize) MPI as required //- Destructor. Shutdown (finalize) MPI as required
~ParRunControl() ~ParRunControl()
{ {
@ -81,27 +98,56 @@ public:
} }
// Parallel Control // Member Functions - General Control
//- Initialize Pstream for a parallel run //- Return the dry-run level (default: 0)
void runPar(int& argc, char**& argv, bool needsThread) int dryRun() const noexcept { return dryRun_; }
//- Increase the dry-run level
void incrDryRun(int level = 1) noexcept { dryRun_ += level; }
//- Change dry-run level, returns old value
int dryRun(const int level) noexcept
{ {
if (!UPstream::init(argc, argv, needsThread)) int old(dryRun_);
{ dryRun_ = level;
Info<< "Failed to start parallel run" << endl; return old;
UPstream::exit(1);
} }
parallel_ = true;
//- Return the verbosity level (default: 0)
int verbose() const noexcept { return verbose_; }
//- Increase the verbosity level
void incrVerbose(int level = 1) noexcept { verbose_ += level; }
//- Change verbosity level, returns old value
int verbose(const int level) noexcept
{
int old(verbose_);
verbose_ = level;
return old;
} }
//- True if this is a parallel run // Member Functions - Parallel Control
//- True if this is (or will be) a parallel run
bool parRun() const noexcept bool parRun() const noexcept
{ {
return parallel_; return parallel_;
} }
//- True if this is a parallel run and uses distributed roots. //- Set as parallel run on/off, return the previous value.
// Use with \b extreme caution if runPar() has already been
// called.
bool parRun(const bool on) noexcept
{
bool old(parallel_);
parallel_ = on;
return old;
}
//- True if a parallel run and uses distributed roots.
bool distributed() const noexcept bool distributed() const noexcept
{ {
return (parallel_ && distributed_); return (parallel_ && distributed_);
@ -113,35 +159,27 @@ public:
distributed_ = (parallel_ && on); distributed_ = (parallel_ && on);
} }
//- True if MPI threads are desired (default: false)
// General Control bool threads() const noexcept
//- Non-zero if set as 'dry-run'
int dryRun() const noexcept
{ {
return dryRun_; return needsThread_;
} }
//- Change 'dry-run', return old value //- Set preference for use of MPI threads
int dryRun(const int level) noexcept void threads(bool on) noexcept
{ {
int old(dryRun_); needsThread_ = on;
dryRun_ = level;
return old;
} }
//- Non-zero if set as 'verbose' //- Initialize UPstream for a parallel run
int verbose() const noexcept void runPar(int& argc, char**& argv)
{ {
return verbose_; if (!UPstream::init(argc, argv, needsThread_))
{
Info<< "Failed to start parallel run" << endl;
UPstream::exit(1);
} }
parallel_ = true;
//- Change 'verbose', return old value
int verbose(const int level) noexcept
{
int old(verbose_);
verbose_ = level;
return old;
} }
}; };

View File

@ -282,12 +282,16 @@ bool Foam::UPstream::init(int& argc, char**& argv, const bool needsThread)
if (UPstream::debug) if (UPstream::debug)
{ {
Pout<< "UPstream::init :" Pout<< "UPstream::init :"
<< " thread-support : wanted:" << needsThread << " thread-support : requested:" << needsThread
<< " obtained:" << " obtained:"
<< ( << (
provided_thread_support == MPI_THREAD_MULTIPLE (provided_thread_support == MPI_THREAD_SINGLE)
? "MPI_THREAD_MULTIPLE" ? "SINGLE"
: "MPI_THREAD_SINGLE" : (provided_thread_support == MPI_THREAD_SERIALIZED)
? "SERIALIZED"
: (provided_thread_support == MPI_THREAD_MULTIPLE)
? "MULTIPLE"
: "other"
) )
<< " procs:" << numprocs << " procs:" << numprocs
<< " rank:" << myRank << " rank:" << myRank