mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: extend flexibility of abort function object (#1119)
- Now also responds to the contents of the trigger file, processing action= contents similar to used with external coupling. Previously it only handled an action that was defined in the dictionary. With this update, the user can chose a diferent action simply by echoing the appropriate action string into the trigger file.
This commit is contained in:
@ -40,10 +40,11 @@ namespace Foam
|
||||
Foam::word Foam::externalFileCoupler::lockName = "OpenFOAM";
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// file-scope
|
||||
// Read file contents and return a stop control as follows:
|
||||
// - contains "done" (should actually be status=done, but we are generous) :
|
||||
// The master (OpenFOAM) has signalled that it is done. Report as <endTime>
|
||||
@ -86,6 +87,7 @@ static enum Time::stopAtControls getStopAction(const std::string& filename)
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::externalFileCoupler::externalFileCoupler()
|
||||
|
||||
@ -30,6 +30,7 @@ License
|
||||
#include "OSspecific.H"
|
||||
#include "PstreamReduceOps.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
#include <fstream>
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -51,15 +52,54 @@ namespace functionObjects
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
// file-scope
|
||||
// Long description for the action name
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Read file contents and return a stop control as follows:
|
||||
//
|
||||
// - action=writeNow, action=nextWrite action=noWriteNow :
|
||||
// The signalled action. Report as corresponding <action>.
|
||||
//
|
||||
// Anything else (empty file, no action=, etc) is reported as <unknown>.
|
||||
//
|
||||
static enum Time::stopAtControls getStopAction(const std::string& filename)
|
||||
{
|
||||
// Slurp entire input file (must exist) as a single string
|
||||
std::string fileContent;
|
||||
|
||||
std::ifstream is(filename);
|
||||
std::getline(is, fileContent, '\0');
|
||||
|
||||
const auto equals = fileContent.find('=');
|
||||
|
||||
if (equals != std::string::npos)
|
||||
{
|
||||
const word actionName(word::validate(fileContent.substr(equals+1)));
|
||||
|
||||
return
|
||||
Time::stopAtControlNames
|
||||
(
|
||||
actionName,
|
||||
Time::stopAtControls::saUnknown
|
||||
);
|
||||
}
|
||||
|
||||
return Time::stopAtControls::saUnknown;
|
||||
}
|
||||
|
||||
|
||||
// Long description for the action name
|
||||
static std::string longDescription(const Time::stopAtControls ctrl)
|
||||
{
|
||||
switch (ctrl)
|
||||
{
|
||||
case Foam::Time::saNoWriteNow :
|
||||
case Time::saEndTime :
|
||||
{
|
||||
return "continue simulation to the endTime";
|
||||
break;
|
||||
}
|
||||
|
||||
case Time::saNoWriteNow :
|
||||
{
|
||||
return "stop without writing data";
|
||||
break;
|
||||
@ -80,12 +120,13 @@ static std::string longDescription(const Time::stopAtControls ctrl)
|
||||
default:
|
||||
{
|
||||
// Invalid choices already filtered out by Enum
|
||||
return "abort";
|
||||
return "unknown action";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
@ -99,18 +140,16 @@ Foam::functionObjects::abort::abort
|
||||
:
|
||||
functionObject(name),
|
||||
time_(runTime),
|
||||
abortFile_(time_.globalPath()/name),
|
||||
action_(Time::stopAtControls::saNextWrite),
|
||||
file_(),
|
||||
defaultAction_(Time::stopAtControls::saUnknown),
|
||||
triggered_(false)
|
||||
{
|
||||
abortFile_.clean();
|
||||
|
||||
read(dict);
|
||||
|
||||
// Cleanup old files from previous runs
|
||||
if (Pstream::master())
|
||||
{
|
||||
Foam::rm(abortFile_);
|
||||
Foam::rm(file_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,36 +160,38 @@ bool Foam::functionObjects::abort::read(const dictionary& dict)
|
||||
{
|
||||
functionObject::read(dict);
|
||||
|
||||
if (dict.readIfPresent("file", abortFile_))
|
||||
{
|
||||
abortFile_.expand();
|
||||
file_.clear();
|
||||
|
||||
if (!abortFile_.isAbsolute())
|
||||
if (dict.readIfPresent("file", file_))
|
||||
{
|
||||
abortFile_ = time_.globalPath()/abortFile_;
|
||||
abortFile_.clean();
|
||||
file_.expand();
|
||||
|
||||
if (!file_.isAbsolute() && file_.size())
|
||||
{
|
||||
file_ = time_.globalPath()/file_;
|
||||
file_.clean();
|
||||
}
|
||||
}
|
||||
|
||||
const auto oldAction = action_;
|
||||
// Ensure we always have a reasonable default file
|
||||
if (file_.empty())
|
||||
{
|
||||
file_ = time_.globalPath()/name();
|
||||
file_.clean();
|
||||
}
|
||||
|
||||
action_ = Time::stopAtControlNames.lookupOrDefault
|
||||
triggered_ = false;
|
||||
|
||||
defaultAction_ = Time::stopAtControlNames.lookupOrDefault
|
||||
(
|
||||
"action",
|
||||
dict,
|
||||
Time::stopAtControls::saNextWrite
|
||||
);
|
||||
|
||||
// User can change action and re-trigger the abort.
|
||||
// eg, they had nextWrite, but actually wanted writeNow.
|
||||
if (oldAction != action_)
|
||||
{
|
||||
triggered_ = false;
|
||||
}
|
||||
|
||||
Info<< type() << " activated ("
|
||||
<< longDescription(action_).c_str() <<")" << nl
|
||||
<< " File: " << abortFile_ << endl;
|
||||
<< longDescription(defaultAction_).c_str() <<")" << nl
|
||||
<< " File: " << file_ << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -161,22 +202,35 @@ bool Foam::functionObjects::abort::execute()
|
||||
// If it has been triggered (eg, nextWrite) don't need to check it again
|
||||
if (!triggered_)
|
||||
{
|
||||
bool hasAbort = (Pstream::master() && isFile(abortFile_));
|
||||
Pstream::scatter(hasAbort);
|
||||
auto action = Time::stopAtControls::saUnknown;
|
||||
|
||||
if (hasAbort)
|
||||
if (Pstream::master() && Foam::isFile(file_))
|
||||
{
|
||||
triggered_ = time_.stopAt(action_);
|
||||
action = getStopAction(file_);
|
||||
|
||||
if (Time::stopAtControls::saUnknown == action)
|
||||
{
|
||||
// An unknown action means an empty file or bad content.
|
||||
// Treat as a request for the default action.
|
||||
|
||||
action = defaultAction_;
|
||||
}
|
||||
}
|
||||
|
||||
// Send to slaves. Also acts as an MPI barrier
|
||||
label intAction(action);
|
||||
Pstream::scatter(intAction);
|
||||
|
||||
action = Time::stopAtControls(intAction);
|
||||
|
||||
// Call stopAt() on all processes
|
||||
triggered_ = time_.stopAt(action);
|
||||
|
||||
if (triggered_)
|
||||
{
|
||||
Info<< "USER REQUESTED ABORT (timeIndex="
|
||||
<< time_.timeIndex()
|
||||
<< "): " << longDescription(action_).c_str()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
Pstream::scatter(triggered_);
|
||||
<< time_.timeIndex() << "): "
|
||||
<< longDescription(action).c_str() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,10 +246,10 @@ bool Foam::functionObjects::abort::write()
|
||||
|
||||
bool Foam::functionObjects::abort::end()
|
||||
{
|
||||
// Cleanup ABORT file
|
||||
// Cleanup trigger file
|
||||
if (Pstream::master())
|
||||
{
|
||||
Foam::rm(abortFile_);
|
||||
Foam::rm(file_);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -28,24 +28,56 @@ Group
|
||||
grpUtilitiesFunctionObjects
|
||||
|
||||
Description
|
||||
Watches for presence of the named file in the case directory
|
||||
and aborts the calculation if it is present.
|
||||
Watches for presence of the named trigger file in the case directory
|
||||
and signals a simulation stop (or other) event if found.
|
||||
|
||||
The presence of the abort file is only checked on the master process.
|
||||
The presence of the trigger file is only checked on the master process.
|
||||
|
||||
Currently the following action types are supported:
|
||||
- noWriteNow
|
||||
- writeNow
|
||||
- nextWrite
|
||||
|
||||
Example of function object specification:
|
||||
\verbatim
|
||||
abort
|
||||
{
|
||||
type abort;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
|
||||
file "<case>/GOODBYE";
|
||||
action writeNow
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
\heading Function object usage
|
||||
\table
|
||||
Property | Description | Required | Default value
|
||||
Property | Description | Required | Default
|
||||
type | Type name: abort | yes |
|
||||
file | The abort filename | no | \<case\>/name
|
||||
action | Abort action | no | nextWrite
|
||||
file | The trigger filename | no | \<case\>/name
|
||||
action | The default action to trigger | no | nextWrite
|
||||
\endtable
|
||||
|
||||
When the trigger file is found, it is checked for the following
|
||||
content which corresponds to actions.
|
||||
|
||||
- \c action=noWriteNow
|
||||
: triggers Foam::Time::saNoWriteNow (stop without writing data)
|
||||
- \c action=writeNow
|
||||
: triggers Foam::Time::saWriteNow (stop and write data)
|
||||
- \c action=nextWrite
|
||||
: triggers Foam::Time::saNextWrite (stop after next normal data write)
|
||||
- \c action=endTime
|
||||
: triggers Foam::Time::saEndTime (continue simulation to the end)
|
||||
- Anything else (empty file, no action=, ...)
|
||||
: use the default action
|
||||
.
|
||||
|
||||
Note
|
||||
The trigger file is considered "sticky". This means that once detected
|
||||
and processed, the trigger is duly noted and the file will not be
|
||||
rechecked. It is not possible or desirable to 'untrigger' an action.
|
||||
|
||||
SourceFiles
|
||||
abort.C
|
||||
|
||||
@ -72,18 +104,18 @@ class abort
|
||||
:
|
||||
public functionObject
|
||||
{
|
||||
// Private data
|
||||
// Private Data
|
||||
|
||||
//- Reference to the Time
|
||||
const Time& time_;
|
||||
|
||||
//- The fully-qualified name of the abort file
|
||||
fileName abortFile_;
|
||||
//- The fully-qualified name of the trigger file
|
||||
fileName file_;
|
||||
|
||||
//- The type of action
|
||||
Time::stopAtControls action_;
|
||||
//- The default action (defined in dictionary)
|
||||
Time::stopAtControls defaultAction_;
|
||||
|
||||
//- Only trigger action once
|
||||
//- Only trigger the action once
|
||||
bool triggered_;
|
||||
|
||||
|
||||
@ -122,13 +154,13 @@ public:
|
||||
//- Read the dictionary settings
|
||||
virtual bool read(const dictionary& dict);
|
||||
|
||||
//- Check existence of abort file and take action
|
||||
//- Check existence of the file and take action
|
||||
virtual bool execute();
|
||||
|
||||
//- No-op
|
||||
virtual bool write();
|
||||
|
||||
//- Remove abort file after the final time-loop.
|
||||
//- Remove the trigger file after the final time-loop.
|
||||
virtual bool end();
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
// OpenFOAM dictionary -*- C++ -*-
|
||||
|
||||
abort
|
||||
{
|
||||
type abort;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
|
||||
file "<case>/ABORT"; // Instead of default name
|
||||
|
||||
// action writeNow; // If we want to see immediate results
|
||||
|
||||
// Or use default (nextWrite) and force with
|
||||
// "action=writeNow" in the trigger file
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -47,5 +47,9 @@ graphFormat raw;
|
||||
|
||||
runTimeModifiable true;
|
||||
|
||||
functions
|
||||
{
|
||||
#include "abort"
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
Reference in New Issue
Block a user