ENH: add -verbose support into argList

- similar to -dry-run handling, can be interrogated from argList,
  which makes it simpler to add into utilities.

- support multiple uses of -dry-run and -verbose to increase the
  level. For example, could have

    someApplication -verbose -verbose

 and inside of the application:

    if (args.verbose() > 2) ...

BUG: error with empty distributed roots specification (fixes #2196)

- previously used the size of distributed roots to transmit if the
  case was running in distributed mode, but this behaves rather poorly
  with bad input. Specifically, the following questionable setup:

      distributed true;
      roots ( /*none*/ );

  Now transmit the ParRunControl distributed() value instead,
  and also emit a gentle warning for the user:

      WARNING: running distributed but did not specify roots!
This commit is contained in:
Mark Olesen 2021-11-05 21:02:21 +01:00
parent c45c649d15
commit 5a121119e6
16 changed files with 249 additions and 135 deletions

View File

@ -121,6 +121,9 @@ int main(int argc, char *argv[])
argList::addArgument("label");
argList::noMandatoryArgs();
argList::addDryRunOption("Just for testing");
argList::addVerboseOption("Increase verbosity");
#include "setRootCase.H"
Pout<< "command-line ("
@ -133,6 +136,10 @@ int main(int argc, char *argv[])
<< "globalPath: " << args.globalPath() << nl
<< nl;
Pout<< "dry-run: " << args.dryRun()
<< " verbose: " << args.verbose() << nl;
if (args.found("relative"))
{
Pout<< "input path: " << args["relative"] << nl

View File

@ -57,9 +57,8 @@ int main(int argc, char *argv[])
#include "addAllRegionOptions.H"
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"more information about decomposition"
);
@ -71,7 +70,6 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
const auto decompFile = args.get<fileName>(1);
const bool verbose = args.found("verbose");
// Set time from database
#include "createTime.H"
@ -146,7 +144,7 @@ int main(int argc, char *argv[])
nDomains
);
if (verbose)
if (args.verbose())
{
info.printDetails(Info);
Info<< nl;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2017-2020 OpenCFD Ltd.
Copyright (C) 2017-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -56,7 +56,7 @@ int main(int argc, char *argv[])
argList::noParallel();
argList::noFunctionObjects();
argList::addArgument("start size .. startN sizeN");
argList::addOption("verbose");
argList::addVerbose("enable labelRange::debug");
argList::addNote
(
"The default is to add ranges, use 'add' and 'del' to toggle\n\n"
@ -65,7 +65,7 @@ int main(int argc, char *argv[])
argList args(argc, argv, false, true);
if (args.found("verbose"))
if (args.verbose())
{
labelRange::debug = 1;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -124,16 +124,13 @@ int main(int argc, char *argv[])
"(vector angle)",
"Rotate about the <vector> by <angle> degrees - eg, '((1 0 0) 45)'"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
"Report euler angles"
);
argList args(argc, argv);
const bool verbose = args.found("verbose");
vector rotVector;
@ -327,7 +324,7 @@ int main(int argc, char *argv[])
tensor rotQ(quaternion(order, angles).R());
tensor rotE(euler::rotation(order, angles, false));
if (verbose)
if (args.verbose())
{
Info<< "euler " << orderName << angles << nl;
printRotation(rotE);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
Copyright (C) 2020-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -50,18 +50,16 @@ int main(int argc, char *argv[])
argList::addArgument("string .. stringN");
argList::addOption("file", "name");
argList::addOption("repeat", "count");
argList::addBoolOption("verbose", "report for each repeat");
argList::addVerboseOption("report each repeat");
argList args(argc, argv, false, true);
const label repeat = args.getOrDefault<label>("repeat", 1);
const bool optVerbose = args.found("verbose");
cpuTime timer;
for (label count = 0; count < repeat; ++count)
{
const bool verbose = (optVerbose || count == 0);
const bool verbose = (args.verbose() || count == 0);
for (label argI=1; argI < args.size(); ++argI)
{
@ -120,7 +118,7 @@ int main(int argc, char *argv[])
for (label count = 0; count < repeat; ++count)
{
const bool verbose = (optVerbose || count == 0);
const bool verbose = (args.verbose() || count == 0);
label nTokens = 0;
if (count)

View File

@ -78,9 +78,8 @@ int main(int argc, char *argv[])
"detail",
"Additional detail"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
);
@ -94,7 +93,6 @@ int main(int argc, char *argv[])
const bool testOr = args.found("or");
const bool detail = args.found("detail");
const bool verbose = args.found("verbose");
label ngood = 0;
label nbad = 0;
@ -127,7 +125,7 @@ int main(int argc, char *argv[])
{
++ngood;
if (verbose)
if (args.verbose())
{
const word addr(Foam::name(ptr));

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2020 OpenCFD Ltd.
Copyright (C) 2016-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -101,9 +101,8 @@ int main(int argc, char *argv[])
"rm",
"Remove selected time directories"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Report progress of -rm option"
);
profiling::disable(); // Disable profiling (and its output)
@ -111,7 +110,7 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
const bool removeFiles(args.found("rm"));
bool verbose(args.found("verbose"));
bool verbose(args.verbose());
// Get times list from the master processor and subset based on

View File

@ -232,9 +232,8 @@ int main(int argc, char *argv[])
(
"Report action without moving/renaming"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
);
@ -247,7 +246,7 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
dryrun = args.dryRun();
verbose = args.found("verbose");
verbose = args.verbose();
// Construct time

View File

@ -330,9 +330,8 @@ int main(int argc, char *argv[])
"Test without writing the decomposition. "
"Changes -cellDist to only write VTK output."
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
);
argList::addOption
@ -409,9 +408,7 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
const bool dryrun = args.dryRun();
const bool writeCellDist = args.found("cellDist");
const bool verbose = args.found("verbose");
// Most of these are ignored for dry-run (not triggered anywhere)
const bool copyZero = args.found("copyZero");
@ -432,7 +429,7 @@ int main(int argc, char *argv[])
// Allow override of time (unless dry-run)
instantList times;
if (dryrun)
if (args.dryRun())
{
Info<< "\ndry-run: ignoring -copy*, -fields, -force, time selection"
<< nl;
@ -477,7 +474,7 @@ int main(int argc, char *argv[])
regionName == polyMesh::defaultRegion ? word::null : regionName
);
if (dryrun)
if (args.dryRun())
{
Info<< "dry-run: decomposing mesh " << regionName << nl << nl
<< "Create mesh..." << flush;
@ -498,7 +495,7 @@ int main(int argc, char *argv[])
args.getOrDefault<word>("method", word::null)
);
decompTest.execute(writeCellDist, verbose);
decompTest.execute(writeCellDist, args.verbose());
continue;
}

View File

@ -72,24 +72,19 @@ int main(int argc, char *argv[])
"Suppress calculation/display of point interpolators"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
);
#include "addRegionOption.H"
#include "setRootCase.H"
#include "createTime.H"
const bool noInterpolate = args.found("no-interpolate");
// const bool verbose = args.found("verbose");
args.readIfPresent("visual-length", lumpedPointState::visLength);
#include "createTime.H"
if (args.dryRun())
{
// Create without a mesh

View File

@ -553,9 +553,8 @@ int main(int argc, char *argv[])
(
"Evaluate but do not write"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity",
true // Advanced option
);
@ -662,9 +661,6 @@ int main(int argc, char *argv[])
#include "createTime.H"
const bool dryrun = args.dryRun();
const bool verbose = args.found("verbose");
const word dictName("setExprFieldsDict");
instantList times = timeSelector::select0(runTime, args);
@ -797,7 +793,7 @@ int main(int argc, char *argv[])
setExprFieldsControl ctrl;
ctrl.dryRun = dryrun;
ctrl.dryRun = args.dryRun();
ctrl.debugParsing = args.found("debug-parser");
ctrl.cacheVariables = !args.found("no-variable-caching");
@ -869,7 +865,7 @@ int main(int argc, char *argv[])
setExprFieldsControl ctrl;
ctrl.dryRun = dryrun;
ctrl.dryRun = args.dryRun();
ctrl.debugParsing = args.found("debug-parser");
ctrl.cacheVariables = !args.found("no-variable-caching");
@ -934,7 +930,7 @@ int main(int argc, char *argv[])
ctrl.useDimensions = bool(dimPtr);
}
if (verbose && !timei)
if (args.verbose() && !timei)
{
// Report once
Info<< "Processing" << dict << nl;

View File

@ -308,9 +308,8 @@ int main(int argc, char *argv[])
"Split surface along non-manifold edges "
"(default split is fully disconnected)"
);
argList::addBoolOption
argList::addVerboseOption
(
"verbose",
"Additional verbosity"
);
argList::addBoolOption

View File

@ -28,6 +28,7 @@ License
#include "argList.H"
#include "OSspecific.H"
#include "Switch.H"
#include "clock.H"
#include "dictionary.H"
#include "IOobject.H"
@ -110,7 +111,7 @@ Foam::argList::initValidTables::initValidTables()
(
"opt-switch",
"name=val",
"Specify the value of a registered optimisation switch (int/bool)."
"Specify the value of a registered optimisation switch."
" Default is 1 if the value is omitted."
" (Can be used multiple times)",
true // advanced option
@ -326,7 +327,7 @@ void Foam::argList::addBoolOption
bool advanced
)
{
addOption(optName, "", usage, advanced);
argList::addOption(optName, "", usage, advanced);
}
@ -455,7 +456,17 @@ void Foam::argList::addDryRunOption
bool advanced
)
{
addOption("dry-run", "", usage, advanced);
argList::addBoolOption("dry-run", usage, advanced);
}
void Foam::argList::addVerboseOption
(
const string& usage,
bool advanced
)
{
argList::addBoolOption("verbose", usage, advanced);
}
@ -469,7 +480,7 @@ void Foam::argList::noFunctionObjects(bool addWithOption)
if (addWithOption)
{
addBoolOption
argList::addBoolOption
(
"withFunctionObjects",
"Execute functionObjects",
@ -487,7 +498,7 @@ void Foam::argList::noJobInfo()
void Foam::argList::noLibs()
{
addBoolOption
argList::addBoolOption
(
"no-libs",
"Disable use of the controlDict libs entry",
@ -768,11 +779,6 @@ void Foam::argList::setCasePaths()
// Executable name, unless already present in the environment
setEnv("FOAM_EXECUTABLE", executable_, false);
if (validOptions.found("dry-run") && options_.found("dry-run"))
{
runControl_.dryRun(true);
}
}
@ -847,6 +853,9 @@ Foam::argList::argList
// Set executable name immediately - useful when emitting errors.
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
int nArgs = 1;
for (int argi = 1; argi < args_.size(); ++argi)
@ -862,15 +871,31 @@ Foam::argList::argList
{
Warning
<< "Ignoring lone '-' on the command-line" << endl;
continue;
}
else if
// Option known and expects an argument?
// - use Switch for a tri-state
// True : known option, expects a parameter
// False : known option, no parameter
// bad() : unknown option
Switch wantArg(Switch::INVALID);
auto optIter = validOptions.cfind(optName);
if
(
validOptions.lookup(optName, "").size()
|| validParOptions.lookup(optName, "").size()
optIter.found()
|| (optIter = validParOptions.cfind(optName)).found()
)
{
// If the option is known to require an argument,
// get it or emit a FatalError.
wantArg = !optIter.val().empty();
}
if (wantArg)
{
// Known option and expects a parameter
// - get it or emit a FatalError.
++argi;
if (argi >= args_.size())
@ -883,12 +908,16 @@ Foam::argList::argList
<< "See '" << executable_ << " -help' for usage"
<< nl << nl;
Pstream::exit(1); // works for serial and parallel
Pstream::exit(1); // works for serial and parallel
}
commandLine_ += ' ';
commandLine_ += args_[argi];
//
// Special handling of these options
//
if (strcmp(optName, "lib") == 0)
{
// The '-lib' option:
@ -921,7 +950,7 @@ Foam::argList::argList
}
else
{
// Regular option:
// Regular option (with a parameter):
// Duplicates handled by using the last -option specified
options_.set(optName, args_[argi]);
}
@ -932,6 +961,19 @@ Foam::argList::argList
// registered as existing.
options_.insert(optName, "");
// Special increment handling for some known flags
if (wantArg.good())
{
if (strcmp(optName, "dry-run") == 0)
{
++numDryRun;
}
else if (strcmp(optName, "verbose") == 0)
{
++numVerbose;
}
}
}
}
else
@ -944,6 +986,10 @@ Foam::argList::argList
}
}
// Commit number of -dry-run and -verbose flag occurrences
runControl_.dryRun(numDryRun);
runControl_.verbose(numVerbose);
args_.resize(nArgs);
parse(checkArgs, checkOpts, initialise);
@ -1043,7 +1089,7 @@ void Foam::argList::parse
foamVersion::printBuildInfo(Info.stdStream(), false);
FatalError.write(Info, false);
Pstream::exit(1); // works for serial and parallel
Pstream::exit(1); // works for serial and parallel
}
if (initialise)
@ -1227,7 +1273,13 @@ void Foam::argList::parse
{
source = "-roots";
runControl_.distributed(true);
if (roots.size() != 1)
if (roots.empty())
{
FatalErrorInFunction
<< "The -roots option must contain values"
<< exit(FatalError);
}
if (roots.size() > 1)
{
dictNProcs = roots.size()+1;
}
@ -1235,17 +1287,27 @@ void Foam::argList::parse
else if (options_.found("hostRoots"))
{
source = "-hostRoots";
roots.resize(Pstream::nProcs()-1, fileName::null);
runControl_.distributed(true);
ITstream is(this->lookup("hostRoots"));
List<Tuple2<wordRe, fileName>> hostRoots(is);
checkITstream(is, "hostRoots");
if (hostRoots.empty())
{
FatalErrorInFunction
<< "The -hostRoots option must contain values"
<< exit(FatalError);
}
// Match machine names to roots
roots.resize(Pstream::nProcs()-1, fileName::null);
for (const auto& hostRoot : hostRoots)
{
labelList matched
(
findStrings(hostRoot.first(), hostMachine)
findMatchingStrings(hostRoot.first(), hostMachine)
);
for (const label matchi : matched)
{
@ -1275,7 +1337,7 @@ void Foam::argList::parse
}
}
if (roots.size() != 1)
if (roots.size() > 1)
{
dictNProcs = roots.size()+1;
}
@ -1312,6 +1374,13 @@ void Foam::argList::parse
nDomainsMandatory = true;
runControl_.distributed(true);
decompDict.readEntry("roots", roots);
if (roots.empty())
{
DetailInfo
<< "WARNING: running distributed"
<< " but did not specify roots!" << nl;
}
}
// Get numberOfSubdomains if it exists.
@ -1330,7 +1399,7 @@ void Foam::argList::parse
{
// Optional if using default location
DetailInfo
<< "Warning: running without decomposeParDict "
<< "WARNING: running without decomposeParDict "
<< this->relativePath(source) << nl;
}
else
@ -1415,8 +1484,13 @@ void Foam::argList::parse
{
options_.set("case", roots[subproci-1]/globalCase_);
OPstream toSubproc(Pstream::commsTypes::scheduled, subproci);
toSubproc << args_ << options_ << roots.size();
OPstream toProc(Pstream::commsTypes::scheduled, subproci);
toProc
<< args_ << options_
<< runControl_.distributed()
<< label(runControl_.dryRun())
<< label(runControl_.verbose());
}
options_.erase("case");
@ -1463,24 +1537,34 @@ void Foam::argList::parse
// Distribute the master's argument list (unaltered)
for (const int subproci : Pstream::subProcs())
{
OPstream toSubproc(Pstream::commsTypes::scheduled, subproci);
toSubproc << args_ << options_ << roots.size();
OPstream toProc(Pstream::commsTypes::scheduled, subproci);
toProc
<< args_ << options_
<< runControl_.distributed()
<< label(runControl_.dryRun())
<< label(runControl_.verbose());
}
}
}
else
{
// Collect the master's argument list
label nroots;
bool isDistributed;
label numDryRun, numVerbose;
IPstream fromMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
fromMaster >> args_ >> options_ >> nroots;
fromMaster
>> args_ >> options_
>> isDistributed
>> numDryRun >> numVerbose;
runControl_.distributed(nroots);
runControl_.distributed(isDistributed);
runControl_.dryRun(numDryRun);
runControl_.verbose(numVerbose);
// Establish rootPath_/globalCase_/case_ for sub-process
setCasePaths();

View File

@ -366,16 +366,23 @@ public:
//- Return the run control (parallel, dry-run etc)
inline const ParRunControl& runControl() const noexcept;
//- Return the dryRun flag
inline bool dryRun() const noexcept;
//- Modify the dryRun flag
inline bool dryRun(const bool on) noexcept;
//- Return distributed flag
//- (i.e. are rootPaths different on different machines)
inline bool distributed() const noexcept;
//- Return the dry-run flag
inline int dryRun() const noexcept;
//- Modify the dry-run flag
inline int dryRun(const int level) noexcept;
//- Return the verbose flag
inline int verbose() const noexcept;
//- Modify the verbose flag
inline int verbose(const int level) noexcept;
//- Mutable access to the loaded dynamic libraries
inline dlLibraryTable& libs() const noexcept;
@ -603,10 +610,17 @@ public:
// Queries the Foam::infoDetailLevel flag.
static bool bannerEnabled();
//- Add a 'dry-run' bool option to validOptions with usage information
//- Enable a 'dry-run' bool option, with usage information
static void addDryRunOption
(
const string& usage, //! usage information (mandatory)
const string& usage, //! usage information (expected)
bool advanced = false
);
//- Enable a 'verbose' bool option, with usage information
static void addVerboseOption
(
const string& usage, //! usage information (expected)
bool advanced = false
);

View File

@ -107,21 +107,33 @@ Foam::argList::runControl() const noexcept
}
inline bool Foam::argList::dryRun() const noexcept
inline bool Foam::argList::distributed() const noexcept
{
return runControl_.distributed();
}
inline int Foam::argList::dryRun() const noexcept
{
return runControl_.dryRun();
}
inline bool Foam::argList::dryRun(const bool on) noexcept
inline int Foam::argList::dryRun(const int level) noexcept
{
return runControl_.dryRun(on);
return runControl_.dryRun(level);
}
inline bool Foam::argList::distributed() const noexcept
inline int Foam::argList::verbose() const noexcept
{
return runControl_.distributed();
return runControl_.verbose();
}
inline int Foam::argList::verbose(const int level) noexcept
{
return runControl_.verbose(level);
}

View File

@ -54,7 +54,8 @@ namespace Foam
class ParRunControl
{
bool dryRun_;
int dryRun_;
int verbose_;
bool parallel_;
bool distributed_;
@ -63,7 +64,8 @@ public:
//- Default construct
ParRunControl()
:
dryRun_(false),
dryRun_(0),
verbose_(0),
parallel_(false),
distributed_(false)
{}
@ -79,49 +81,68 @@ public:
}
//- Initialize Pstream for a parallel run
void runPar(int& argc, char**& argv, bool needsThread)
{
if (!UPstream::init(argc, argv, needsThread))
// Parallel Control
//- Initialize Pstream for a parallel run
void runPar(int& argc, char**& argv, bool needsThread)
{
Info<< "Failed to start parallel run" << endl;
UPstream::exit(1);
if (!UPstream::init(argc, argv, needsThread))
{
Info<< "Failed to start parallel run" << endl;
UPstream::exit(1);
}
parallel_ = true;
}
parallel_ = true;
}
//- True if set as 'dry-run'
bool dryRun() const noexcept
{
return dryRun_;
}
//- True if this is a parallel run
bool parRun() const noexcept
{
return parallel_;
}
//- Set as 'dry-run', return old value
bool dryRun(bool on) noexcept
{
bool old(dryRun_);
dryRun_ = on;
return old;
}
//- True if this is a parallel run and uses distributed roots.
bool distributed() const noexcept
{
return (parallel_ && distributed_);
}
//- True if this is a parallel run
bool parRun() const noexcept
{
return parallel_;
}
//- Set use of distributed roots, but only if actually parallel
void distributed(bool on) noexcept
{
distributed_ = (parallel_ && on);
}
//- True if this is a parallel run and uses distributed roots.
bool distributed() const noexcept
{
return (parallel_ && distributed_);
}
//- Set use of distributed roots, but only if actually parallel
void distributed(bool on) noexcept
{
distributed_ = (parallel_ && on);
}
// General Control
//- Non-zero if set as 'dry-run'
int dryRun() const noexcept
{
return dryRun_;
}
//- Change 'dry-run', return old value
int dryRun(const int level) noexcept
{
int old(dryRun_);
dryRun_ = level;
return old;
}
//- Non-zero if set as 'verbose'
int verbose() const noexcept
{
return verbose_;
}
//- Change 'verbose', return old value
int verbose(const int level) noexcept
{
int old(verbose_);
verbose_ = level;
return old;
}
};