diff --git a/src/finiteVolume/cfdTools/general/coupling/externalFileCoupler.C b/src/finiteVolume/cfdTools/general/coupling/externalFileCoupler.C index 59a0fde68475bdba51e672cf69a5d07839750096..bb17b4cf8a9e5b4eb8f11e0abac6c0e8bdebbe72 100644 --- a/src/finiteVolume/cfdTools/general/coupling/externalFileCoupler.C +++ b/src/finiteVolume/cfdTools/general/coupling/externalFileCoupler.C @@ -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() diff --git a/src/functionObjects/utilities/abort/abort.C b/src/functionObjects/utilities/abort/abort.C index 02d6a69112da53566204f666eefa5f4d7bfa4102..4f480388a38aed008e7245bd9de1ce8461305666 100644 --- a/src/functionObjects/utilities/abort/abort.C +++ b/src/functionObjects/utilities/abort/abort.C @@ -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_)) + file_.clear(); + + if (dict.readIfPresent("file", file_)) { - abortFile_.expand(); + file_.expand(); - if (!abortFile_.isAbsolute()) + if (!file_.isAbsolute() && file_.size()) { - abortFile_ = time_.globalPath()/abortFile_; - abortFile_.clean(); - } + 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 (triggered_) + if (Time::stopAtControls::saUnknown == action) { - Info<< "USER REQUESTED ABORT (timeIndex=" - << time_.timeIndex() - << "): " << longDescription(action_).c_str() - << endl; + // An unknown action means an empty file or bad content. + // Treat as a request for the default action. + + action = defaultAction_; } + } - Pstream::scatter(triggered_); + // 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() { - // Cleanup ABORT file + // Cleanup trigger file if (Pstream::master()) { - Foam::rm(abortFile_); + Foam::rm(file_); } return true; diff --git a/src/functionObjects/utilities/abort/abort.H b/src/functionObjects/utilities/abort/abort.H index c2c86aa564084bb6520c7ba71d0c4cafe6b57e08..86a3958649d41cbd7c4af778a67cf67594a90410 100644 --- a/src/functionObjects/utilities/abort/abort.H +++ b/src/functionObjects/utilities/abort/abort.H @@ -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 - type | Type name: abort | yes | - file | The abort filename | no | \<case\>/name - action | Abort action | no | nextWrite + Property | Description | Required | Default + type | Type name: abort | yes | + 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(); }; diff --git a/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/abort b/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/abort new file mode 100644 index 0000000000000000000000000000000000000000..7001b883ef76b737ec0eac58c73ed64f484b8973 --- /dev/null +++ b/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/abort @@ -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 +} + + +// ************************************************************************* // diff --git a/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/controlDict b/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/controlDict index 1ed4419d731c8ffa57b5dde169e074f121b5780e..fcef92c66784bf02d937b0200f8a9aca7e79bdde 100644 --- a/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/controlDict +++ b/tutorials/compressible/rhoSimpleFoam/squareBendLiq/system/controlDict @@ -47,5 +47,9 @@ graphFormat raw; runTimeModifiable true; +functions +{ + #include "abort" +} // ************************************************************************* //