Commit da332229 authored by Mark Olesen's avatar Mark Olesen Committed by Andrew Heather
Browse files

ENH: add flexible command options for setting Debug and Info switches #1467

For example,

   $ someSolver -info-switch writeOptionalEntries

- note that values changed via the command-line are changed after the
  etc/controlDict entries, but *before* any case-local
  system/controlDict entries.

  However, in many testing cases the command-line options eliminate
  the need for such local file modifications.

ENH: cleanup handling of local debug switches in Time

- add as methods directly on simpleObjectRegistry to avoid code
  duplication

STYLE: adjust internal naming of ITstream parameters
parent b0a999ca
......@@ -3,7 +3,7 @@
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration |
# \\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd.
# \\ / A nd | Copyright (C) 2017-2019 OpenCFD Ltd.
# \\/ M anipulation |
#------------------------------------------------------------------------------
# License
......@@ -146,6 +146,7 @@ HEADER
# -help-man Internal option
# -hostRoots Advanced distributed run option
# -roots Advanced distributed run option
# -debug-switch, -opt-switch, -info-switch, -lib Advanced options
#
# Begin parsing after first appearance of "^[Oo]ptions:"
# Terminate parsing on first appearance of "-help-full"
......@@ -159,6 +160,8 @@ extractOptions()
sed -ne '1,/^[Oo]ptions:/d' \
-e 's/^ *//; /^$/d; /^[^-]/d; /^--/d; /^-help-man/d;' \
-e '/^-hostRoots /d; /^-roots /d;' \
-e '/^-lib /d;' \
-e '/^-[a-z]*-switch /d;' \
-e 'y/,/ /; s/=.*$/=/;' \
-e '/^-[^ ]* </{ s/^\(-[^ ]* <\).*$/\1/; p; d }' \
-e 's/^\(-[^ ]*\).*$/\1/; p; /^-help-full/q;' \
......
......@@ -7,6 +7,7 @@ global/clock/clock.C
global/clockTime/clockTime.C
global/clockValue/clockValue.C
global/cpuTime/cpuTimeCxx.C
global/debug/simpleObjectRegistry.C
global/profiling/profiling.C
global/profiling/profilingInformation.C
global/profiling/profilingSysInfo.C
......
......@@ -149,11 +149,11 @@ public:
//- Construct as copy
ITstream(const ITstream& its)
ITstream(const ITstream& is)
:
Istream(ASCII, currentVersion),
tokenList(its),
name_(its.name_),
tokenList(is),
name_(is.name_),
tokenIndex_(0)
{
setOpened();
......
......@@ -87,7 +87,6 @@ int Foam::Time::printExecutionFormat_
Foam::debug::infoSwitch("printExecutionFormat", 0)
);
registerInfoSwitch
(
"printExecutionFormat",
......
......@@ -109,39 +109,7 @@ void Foam::Time::readDict()
<< "Overriding DebugSwitches according to "
<< controlDict_.name() << nl;
simpleObjectRegistry& objs = debug::debugObjects();
for (const entry& dEntry : *localDict)
{
const word& name = dEntry.keyword();
simpleObjectRegistryEntry* objPtr = objs.lookupPtr(name);
if (objPtr)
{
const List<simpleRegIOobject*>& objects = *objPtr;
DetailInfo << " " << dEntry << nl;
if (dEntry.isDict())
{
for (simpleRegIOobject* obj : objects)
{
OStringStream os(IOstream::ASCII);
os << dEntry.dict();
IStringStream is(os.str());
obj->readData(is);
}
}
else
{
for (simpleRegIOobject* obj : objects)
{
obj->readData(dEntry.stream());
}
}
}
}
debug::debugObjects().setValues(*localDict, true);
}
......@@ -156,39 +124,7 @@ void Foam::Time::readDict()
<< "Overriding InfoSwitches according to "
<< controlDict_.name() << nl;
simpleObjectRegistry& objs = debug::infoObjects();
for (const entry& dEntry : *localDict)
{
const word& name = dEntry.keyword();
simpleObjectRegistryEntry* objPtr = objs.lookupPtr(name);
if (objPtr)
{
const List<simpleRegIOobject*>& objects = *objPtr;
DetailInfo << " " << dEntry << nl;
if (dEntry.isDict())
{
for (simpleRegIOobject* obj : objects)
{
OStringStream os(IOstream::ASCII);
os << dEntry.dict();
IStringStream is(os.str());
obj->readData(is);
}
}
else
{
for (simpleRegIOobject* obj : objects)
{
obj->readData(dEntry.stream());
}
}
}
}
debug::infoObjects().setValues(*localDict, true);
}
// OptimisationSwitches
......@@ -202,39 +138,7 @@ void Foam::Time::readDict()
<< "Overriding OptimisationSwitches according to "
<< controlDict_.name() << nl;
simpleObjectRegistry& objs = debug::optimisationObjects();
for (const entry& dEntry : *localDict)
{
const word& name = dEntry.keyword();
simpleObjectRegistryEntry* objPtr = objs.lookupPtr(name);
if (objPtr)
{
DetailInfo << " " << dEntry << nl;
const List<simpleRegIOobject*>& objects = *objPtr;
if (dEntry.isDict())
{
for (simpleRegIOobject* obj : objects)
{
OStringStream os(IOstream::ASCII);
os << dEntry.dict();
IStringStream is(os.str());
obj->readData(is);
}
}
else
{
for (simpleRegIOobject* obj : objects)
{
obj->readData(dEntry.stream());
}
}
}
}
debug::optimisationObjects().setValues(*localDict, true);
}
......
......@@ -35,6 +35,7 @@ License
#include "labelList.H"
#include "regIOobject.H"
#include "dynamicCode.H"
#include "simpleObjectRegistry.H"
#include "sigFpe.H"
#include "sigInt.H"
#include "sigQuit.H"
......@@ -80,7 +81,38 @@ Foam::argList::initValidTables::initValidTables()
(
"lib",
"name",
"Additional library/libraries to load (can be used multiple times)",
"Additional library or library list to load"
" (can be used multiple times)",
true // advanced option
);
argList::addOption
(
"debug-switch",
"name=val",
"Specify the value of a registered debug switch."
" Default is 1 if the value is omitted."
" (Can be used multiple times)",
true // advanced option
);
argList::addOption
(
"info-switch",
"name=val",
"Specify the value of a registered info switch."
" Default is 1 if the value is omitted."
" (Can be used multiple times)",
true // advanced option
);
argList::addOption
(
"opt-switch",
"name=val",
"Specify the value of a registered optimisation switch (int/bool)."
" Default is 1 if the value is omitted."
" (Can be used multiple times)",
true // advanced option
);
......@@ -815,6 +847,30 @@ Foam::argList::argList
// Append name(s) to libs_ for later opening
libs_.append(this->getList<fileName>(argi));
}
else if (strcmp(optName, "debug-switch") == 0)
{
// The '-debug-switch' option:
// change registered debug switch
DetailInfo << "DebugSwitch ";
debug::debugObjects()
.setNamedInt(args_[argi], 1, true);
}
else if (strcmp(optName, "info-switch") == 0)
{
// The '-info-switch' option:
// change registered info switch
DetailInfo << "InfoSwitch ";
debug::infoObjects()
.setNamedInt(args_[argi], 1, true);
}
else if (strcmp(optName, "opt-switch") == 0)
{
// The '-opt-switch' option:
// change registered optimisation switch
DetailInfo << "OptimisationSwitch ";
debug::optimisationObjects()
.setNamedInt(args_[argi], 1, true);
}
else
{
// Regular option:
......
......@@ -92,7 +92,7 @@ deleteControlDictPtr deleteControlDictPtr_;
namespace Foam
{
// Like dictionary getOrAdd (default), but circumventing
// Like dictionary getOrAdd with LITERAL, but circumventing
// writeOptionalEntries to avoid extremely noisy output
template<class T>
static inline T getOrAdd
......@@ -113,6 +113,26 @@ static inline T getOrAdd
return deflt;
}
// Append object to a registry
static inline void appendNamedEntry
(
simpleObjectRegistry& obr,
const char* name,
simpleRegIOobject* obj
)
{
simpleObjectRegistryEntry* ptr = obr.lookupPtr(name);
if (ptr)
{
ptr->append(obj);
}
else
{
obr.append(name, new simpleObjectRegistryEntry(obj));
}
}
} // End namespace Foam
......@@ -133,19 +153,19 @@ Foam::dictionary& Foam::debug::controlDict()
{
fileNameList controlDictFiles = findEtcFiles("controlDict", true);
controlDictPtr_ = new dictionary();
forAllReverse(controlDictFiles, cdfi)
forAllReverse(controlDictFiles, i)
{
IFstream ifs(controlDictFiles[cdfi]);
IFstream is(controlDictFiles[i]);
if (!ifs.good())
if (!is.good())
{
SafeFatalIOErrorInFunction
(
ifs,
is,
"Cannot open controlDict"
);
}
controlDictPtr_->merge(dictionary(ifs));
controlDictPtr_->merge(dictionary(is));
}
}
}
......@@ -218,11 +238,7 @@ int Foam::debug::optimisationSwitch(const char* name, const int deflt)
}
float Foam::debug::floatOptimisationSwitch
(
const char* name,
const float deflt
)
float Foam::debug::floatOptimisationSwitch(const char* name, const float deflt)
{
return getOrAdd(optimisationSwitches(), name, deflt);
}
......@@ -230,43 +246,13 @@ float Foam::debug::floatOptimisationSwitch
void Foam::debug::addDebugObject(const char* name, simpleRegIOobject* obj)
{
simpleObjectRegistryEntry* ptr = debugObjects().lookupPtr(name);
if (ptr)
{
ptr->append(obj);
}
else
{
debugObjects().append
(
name,
new simpleObjectRegistryEntry
(
List<simpleRegIOobject*>(1, obj)
)
);
}
appendNamedEntry(debugObjects(), name, obj);
}
void Foam::debug::addInfoObject(const char* name, simpleRegIOobject* obj)
{
simpleObjectRegistryEntry* ptr = infoObjects().lookupPtr(name);
if (ptr)
{
ptr->append(obj);
}
else
{
infoObjects().append
(
name,
new simpleObjectRegistryEntry
(
List<simpleRegIOobject*>(1, obj)
)
);
}
appendNamedEntry(infoObjects(), name, obj);
}
......@@ -276,22 +262,7 @@ void Foam::debug::addOptimisationObject
simpleRegIOobject* obj
)
{
simpleObjectRegistryEntry* ptr = optimisationObjects().lookupPtr(name);
if (ptr)
{
ptr->append(obj);
}
else
{
optimisationObjects().append
(
name,
new simpleObjectRegistryEntry
(
List<simpleRegIOobject*>(1, obj)
)
);
}
appendNamedEntry(optimisationObjects(), name, obj);
}
......@@ -301,22 +272,7 @@ void Foam::debug::addDimensionSetObject
simpleRegIOobject* obj
)
{
simpleObjectRegistryEntry* ptr = dimensionSetObjects().lookupPtr(name);
if (ptr)
{
ptr->append(obj);
}
else
{
dimensionSetObjects().append
(
name,
new simpleObjectRegistryEntry
(
List<simpleRegIOobject*>(1, obj)
)
);
}
appendNamedEntry(dimensionSetObjects(), name, obj);
}
......@@ -326,25 +282,7 @@ void Foam::debug::addDimensionedConstantObject
simpleRegIOobject* obj
)
{
simpleObjectRegistryEntry* ptr = dimensionedConstantObjects().lookupPtr
(
name
);
if (ptr)
{
ptr->append(obj);
}
else
{
dimensionedConstantObjects().append
(
name,
new simpleObjectRegistryEntry
(
List<simpleRegIOobject*>(1, obj)
)
);
}
appendNamedEntry(dimensionedConstantObjects(), name, obj);
}
......@@ -406,6 +344,10 @@ Foam::simpleObjectRegistry& Foam::debug::dimensionedConstantObjects()
namespace Foam
{
// Write the switch names.
//
// Use flatOutput with -1 for the length to ensure we always have newlines,
// even if the lists are short
static void listSwitches
(
const wordList& debugSwitches,
......@@ -418,48 +360,50 @@ static void listSwitches
{
fileNameList controlDictFiles = findEtcFiles("controlDict", true);
dictionary controlDict;
forAllReverse(controlDictFiles, cdfi)
forAllReverse(controlDictFiles, i)
{
controlDict.merge(dictionary(IFstream(controlDictFiles[cdfi])()));
IFstream is(controlDictFiles[i]);
controlDict.merge(dictionary(is));
}
wordHashSet controlDictDebug
(
controlDict.subDict("DebugSwitches").toc()
);
IOobject::writeDivider(Info);
wordHashSet controlDictInfo
(
controlDict.subDict("InfoSwitches").toc()
);
// Use a HashSet to track switches that have not been set
wordHashSet hashed;
wordHashSet controlDictOpt
(
controlDict.subDict("OptimisationSwitches").toc()
);
// DebugSwitches
hashed = debugSwitches;
hashed.unset(controlDict.subDict("DebugSwitches").toc());
Info<< "Unset DebugSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
IOobject::writeDivider(Info);
wordHashSet hashset;
hashset = debugSwitches;
hashset -= controlDictDebug;
Info<< "Unset DebugSwitches" << hashset.sortedToc() << nl;
// InfoSwitches
hashed = infoSwitches;
hashed.unset(controlDict.subDict("InfoSwitches").toc());
Info<< "Unset InfoSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
hashset = infoSwitches;
hashset -= controlDictInfo;
Info<< "Unset InfoSwitches" << hashset.sortedToc() << nl;
// OptimisationSwitches
hashed = optSwitches;
hashed.unset(controlDict.subDict("OptimisationSwitches").toc());
hashset = optSwitches;
hashset -= controlDictOpt;
Info<< "Unset OptimisationSwitches" << hashset.sortedToc() << nl;
Info<< "Unset OptimisationSwitches"
<< flatOutput(hashed.sortedToc(), -1) << nl;
}
else
{
IOobject::writeDivider(Info);
Info<< "DebugSwitches" << debugSwitches << nl
<< "InfoSwitches" << infoSwitches << nl
<< "OptimisationSwitches" << optSwitches << nl;
Info<< "DebugSwitches"
<< flatOutput(debugSwitches, -1) << nl
<< "InfoSwitches"
<< flatOutput(infoSwitches, -1) << nl
<< "OptimisationSwitches"
<< flatOutput(optSwitches, -1) << nl;
}
}
......
......@@ -68,13 +68,13 @@ namespace debug
// \sa Foam::findEtcFile()
dictionary& controlDict();
//- The DebugSwitches sub-dictionary in the central controlDict.
//- The DebugSwitches sub-dictionary in the central controlDict(s).
dictionary& debugSwitches();
//- The InfoSwitches sub-dictionary in the central controlDict.
//- The InfoSwitches sub-dictionary in the central controlDict(s).
dictionary& infoSwitches();
//- The OptimisationSwitches sub-dictionary in the central controlDict.
//- The OptimisationSwitches sub-dictionary in the central controlDict(s).
dictionary& optimisationSwitches();
//- Lookup debug switch or add default value.
......@@ -114,22 +114,22 @@ namespace debug
void addDimensionedConstantObject(const char* name, simpleRegIOobject*);
//- Get access to registered debug switch objects
//- Access to registered DebugSwitch objects
simpleObjectRegistry& debugObjects();
//- Get access to registered info switch objects
//- Access to registered InfoSwitch objects
simpleObjectRegistry& infoObjects();
//- Get access to registered optimisation switch objects
//- Access to registered OptimisationSwitch objects
simpleObjectRegistry& optimisationObjects();
//- Get access to registered dimensionSets switch objects
//- Access to registered DimensionSets objects
simpleObjectRegistry& dimensionSetObjects();
//- Get access to registered dimensionedConstant switch objects
//- Access to registered DimensionedConstants objects
simpleObjectRegistry& dimensionedConstantObjects();
//- List registered debug switches
//- List registered debug/info/optimisation switches
void listRegisteredSwitches(const bool unset);
} // End namespace debug
......
......@@ -33,14 +33,14 @@ Description
#include "simpleRegIOobject.H"
#include "debug.H"
#include "label.H"
#include "label.H" // Also for defining Foam::word etc.
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
//- Define the debug information, lookup as \a Name
//- Define the debug information, lookup as \a name
template<class Type>
class RegisterDebugSwitch
:
......@@ -58,12 +58,12 @@ public:
virtual ~RegisterDebugSwitch() = default;
virtual void readData(Foam::Istream& is)
virtual void readData(Istream& is)
{
Type::debug = readLabel(is);
is >> Type::debug;
}