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";
|
Foam::word Foam::externalFileCoupler::lockName = "OpenFOAM";
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
// file-scope
|
|
||||||
// Read file contents and return a stop control as follows:
|
// Read file contents and return a stop control as follows:
|
||||||
// - contains "done" (should actually be status=done, but we are generous) :
|
// - contains "done" (should actually be status=done, but we are generous) :
|
||||||
// The master (OpenFOAM) has signalled that it is done. Report as <endTime>
|
// 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
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::externalFileCoupler::externalFileCoupler()
|
Foam::externalFileCoupler::externalFileCoupler()
|
||||||
|
|||||||
@ -30,6 +30,7 @@ License
|
|||||||
#include "OSspecific.H"
|
#include "OSspecific.H"
|
||||||
#include "PstreamReduceOps.H"
|
#include "PstreamReduceOps.H"
|
||||||
#include "addToRunTimeSelectionTable.H"
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -51,15 +52,54 @@ namespace functionObjects
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
// file-scope
|
|
||||||
// Long description for the action name
|
|
||||||
namespace Foam
|
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)
|
static std::string longDescription(const Time::stopAtControls ctrl)
|
||||||
{
|
{
|
||||||
switch (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";
|
return "stop without writing data";
|
||||||
break;
|
break;
|
||||||
@ -80,12 +120,13 @@ static std::string longDescription(const Time::stopAtControls ctrl)
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// Invalid choices already filtered out by Enum
|
// Invalid choices already filtered out by Enum
|
||||||
return "abort";
|
return "unknown action";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
@ -99,18 +140,16 @@ Foam::functionObjects::abort::abort
|
|||||||
:
|
:
|
||||||
functionObject(name),
|
functionObject(name),
|
||||||
time_(runTime),
|
time_(runTime),
|
||||||
abortFile_(time_.globalPath()/name),
|
file_(),
|
||||||
action_(Time::stopAtControls::saNextWrite),
|
defaultAction_(Time::stopAtControls::saUnknown),
|
||||||
triggered_(false)
|
triggered_(false)
|
||||||
{
|
{
|
||||||
abortFile_.clean();
|
|
||||||
|
|
||||||
read(dict);
|
read(dict);
|
||||||
|
|
||||||
// Cleanup old files from previous runs
|
// Cleanup old files from previous runs
|
||||||
if (Pstream::master())
|
if (Pstream::master())
|
||||||
{
|
{
|
||||||
Foam::rm(abortFile_);
|
Foam::rm(file_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,36 +160,38 @@ bool Foam::functionObjects::abort::read(const dictionary& dict)
|
|||||||
{
|
{
|
||||||
functionObject::read(dict);
|
functionObject::read(dict);
|
||||||
|
|
||||||
if (dict.readIfPresent("file", abortFile_))
|
file_.clear();
|
||||||
{
|
|
||||||
abortFile_.expand();
|
|
||||||
|
|
||||||
if (!abortFile_.isAbsolute())
|
if (dict.readIfPresent("file", file_))
|
||||||
|
{
|
||||||
|
file_.expand();
|
||||||
|
|
||||||
|
if (!file_.isAbsolute() && file_.size())
|
||||||
{
|
{
|
||||||
abortFile_ = time_.globalPath()/abortFile_;
|
file_ = time_.globalPath()/file_;
|
||||||
abortFile_.clean();
|
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",
|
"action",
|
||||||
dict,
|
dict,
|
||||||
Time::stopAtControls::saNextWrite
|
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 ("
|
Info<< type() << " activated ("
|
||||||
<< longDescription(action_).c_str() <<")" << nl
|
<< longDescription(defaultAction_).c_str() <<")" << nl
|
||||||
<< " File: " << abortFile_ << endl;
|
<< " File: " << file_ << endl;
|
||||||
|
|
||||||
return true;
|
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 it has been triggered (eg, nextWrite) don't need to check it again
|
||||||
if (!triggered_)
|
if (!triggered_)
|
||||||
{
|
{
|
||||||
bool hasAbort = (Pstream::master() && isFile(abortFile_));
|
auto action = Time::stopAtControls::saUnknown;
|
||||||
Pstream::scatter(hasAbort);
|
|
||||||
|
|
||||||
if (hasAbort)
|
if (Pstream::master() && Foam::isFile(file_))
|
||||||
{
|
{
|
||||||
triggered_ = time_.stopAt(action_);
|
action = getStopAction(file_);
|
||||||
|
|
||||||
if (triggered_)
|
if (Time::stopAtControls::saUnknown == action)
|
||||||
{
|
{
|
||||||
Info<< "USER REQUESTED ABORT (timeIndex="
|
// An unknown action means an empty file or bad content.
|
||||||
<< time_.timeIndex()
|
// Treat as a request for the default action.
|
||||||
<< "): " << longDescription(action_).c_str()
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pstream::scatter(triggered_);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,10 +246,10 @@ bool Foam::functionObjects::abort::write()
|
|||||||
|
|
||||||
bool Foam::functionObjects::abort::end()
|
bool Foam::functionObjects::abort::end()
|
||||||
{
|
{
|
||||||
// Cleanup ABORT file
|
// Cleanup trigger file
|
||||||
if (Pstream::master())
|
if (Pstream::master())
|
||||||
{
|
{
|
||||||
Foam::rm(abortFile_);
|
Foam::rm(file_);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -28,24 +28,56 @@ Group
|
|||||||
grpUtilitiesFunctionObjects
|
grpUtilitiesFunctionObjects
|
||||||
|
|
||||||
Description
|
Description
|
||||||
Watches for presence of the named file in the case directory
|
Watches for presence of the named trigger file in the case directory
|
||||||
and aborts the calculation if it is present.
|
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:
|
Currently the following action types are supported:
|
||||||
- noWriteNow
|
- noWriteNow
|
||||||
- writeNow
|
- writeNow
|
||||||
- nextWrite
|
- nextWrite
|
||||||
|
|
||||||
|
Example of function object specification:
|
||||||
|
\verbatim
|
||||||
|
abort
|
||||||
|
{
|
||||||
|
type abort;
|
||||||
|
libs ("libutilityFunctionObjects.so");
|
||||||
|
|
||||||
|
file "<case>/GOODBYE";
|
||||||
|
action writeNow
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
\heading Function object usage
|
\heading Function object usage
|
||||||
\table
|
\table
|
||||||
Property | Description | Required | Default value
|
Property | Description | Required | Default
|
||||||
type | Type name: abort | yes |
|
type | Type name: abort | yes |
|
||||||
file | The abort filename | no | \<case\>/name
|
file | The trigger filename | no | \<case\>/name
|
||||||
action | Abort action | no | nextWrite
|
action | The default action to trigger | no | nextWrite
|
||||||
\endtable
|
\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
|
SourceFiles
|
||||||
abort.C
|
abort.C
|
||||||
|
|
||||||
@ -72,18 +104,18 @@ class abort
|
|||||||
:
|
:
|
||||||
public functionObject
|
public functionObject
|
||||||
{
|
{
|
||||||
// Private data
|
// Private Data
|
||||||
|
|
||||||
//- Reference to the Time
|
//- Reference to the Time
|
||||||
const Time& time_;
|
const Time& time_;
|
||||||
|
|
||||||
//- The fully-qualified name of the abort file
|
//- The fully-qualified name of the trigger file
|
||||||
fileName abortFile_;
|
fileName file_;
|
||||||
|
|
||||||
//- The type of action
|
//- The default action (defined in dictionary)
|
||||||
Time::stopAtControls action_;
|
Time::stopAtControls defaultAction_;
|
||||||
|
|
||||||
//- Only trigger action once
|
//- Only trigger the action once
|
||||||
bool triggered_;
|
bool triggered_;
|
||||||
|
|
||||||
|
|
||||||
@ -122,13 +154,13 @@ public:
|
|||||||
//- Read the dictionary settings
|
//- Read the dictionary settings
|
||||||
virtual bool read(const dictionary& dict);
|
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();
|
virtual bool execute();
|
||||||
|
|
||||||
//- No-op
|
//- No-op
|
||||||
virtual bool write();
|
virtual bool write();
|
||||||
|
|
||||||
//- Remove abort file after the final time-loop.
|
//- Remove the trigger file after the final time-loop.
|
||||||
virtual bool end();
|
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;
|
runTimeModifiable true;
|
||||||
|
|
||||||
|
functions
|
||||||
|
{
|
||||||
|
#include "abort"
|
||||||
|
}
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
Reference in New Issue
Block a user