Merge branch 'feature-externalFileCoupler' into 'develop'

Feature external file coupler

See merge request !126
This commit is contained in:
Andrew Heather
2017-07-18 11:12:05 +01:00
25 changed files with 689 additions and 755 deletions

View File

@ -1,3 +0,0 @@
Test-externalCoupler.C
EXE = $(FOAM_USER_APPBIN)/Test-externalCoupler

View File

@ -1,7 +0,0 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/lumpedPointMotion/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-llumpedPointMotion

View File

@ -0,0 +1,3 @@
Test-externalFileCoupler.C
EXE = $(FOAM_USER_APPBIN)/Test-externalFileCoupler

View File

@ -0,0 +1,5 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude
EXE_LIBS = \
-lfiniteVolume

View File

@ -22,14 +22,14 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Application
Test-externalCoupler
Test-externalFileCoupler
Description
Test of master/slave communication etc.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "externalCoupler.H"
#include "externalFileCoupler.H"
using namespace Foam;
@ -47,7 +47,7 @@ int main(int argc, char *argv[])
const label maxCount = args.optionLookupOrDefault<label>("max", 1000);
externalCoupler coupler;
externalFileCoupler coupler;
if (args.optionFound("slave"))
{

View File

@ -29,7 +29,7 @@ Description
points/rotations and the corresponding movement of the building surfaces.
Uses the tabulated responses from the specified file.
Optionally, it can also be used to a dummy responder for the
externalCoupler logic, which makes it useful as a debugging facility
externalFileCoupler logic, which makes it useful as a debugging facility
as well demonstrating how an external application could communicate
with the lumpedPointMovement point-patch boundary condition.
@ -131,7 +131,7 @@ int main(int argc, char *argv[])
{
Info<< "Running as slave responder" << endl;
externalCoupler& coupler = movement().coupler();
externalFileCoupler& coupler = movement().coupler();
label count = 0;
for (label index = 0; index < responseTable.size(); index += span)

View File

@ -45,6 +45,8 @@ Foam::fileStat::fileStat
const bool followLink,
const unsigned int maxTime
)
:
isValid_(false)
{
// Work on volatile
volatile bool locIsValid = false;
@ -76,6 +78,12 @@ Foam::fileStat::fileStat(Istream& is)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::fileStat::size() const
{
return isValid_ ? label(status_.st_size) : 0;
}
bool Foam::fileStat::sameDevice(const fileStat& stat2) const
{
return

View File

@ -55,8 +55,8 @@ namespace Foam
class fileStat;
Istream& operator>>(Istream&, fileStat&);
Ostream& operator<<(Ostream&, const fileStat&);
Istream& operator>>(Istream& is, fileStat& fStat);
Ostream& operator<<(Ostream& os, const fileStat& fStat);
/*---------------------------------------------------------------------------*\
@ -96,7 +96,7 @@ public:
);
//- Construct from Istream
fileStat(Istream&);
fileStat(Istream& is);
// Member Functions
@ -115,6 +115,9 @@ public:
return isValid_;
}
//- Size in bytes. Zero for invalid file-stat.
label size() const;
// Check
@ -130,8 +133,8 @@ public:
// IOstream Operators
friend Istream& operator>>(Istream&, fileStat&);
friend Ostream& operator<<(Ostream&, const fileStat&);
friend Istream& operator>>(Istream& is, fileStat& fStat);
friend Ostream& operator<<(Ostream& os, const fileStat& fStat);
};

View File

@ -411,6 +411,9 @@ $(general)/bound/bound.C
$(general)/CorrectPhi/correctUphiBCs.C
$(general)/pressureControl/pressureControl.C
coupling = $(general)/coupling
$(coupling)/externalFileCoupler.C
solutionControl = $(general)/solutionControl
$(solutionControl)/solutionControl/solutionControl.C
$(solutionControl)/simpleControl/simpleControl.C

View File

@ -23,22 +23,21 @@ License
\*---------------------------------------------------------------------------*/
#include "externalCoupler.H"
#include "externalFileCoupler.H"
#include "Pstream.H"
#include "PstreamReduceOps.H"
#include "OSspecific.H"
#include "IFstream.H"
#include "OFstream.H"
#include "Switch.H"
#include <fstream>
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(externalCoupler, 0);
defineTypeNameAndDebug(externalFileCoupler, 0);
}
Foam::word Foam::externalCoupler::lockName = "OpenFOAM";
Foam::word Foam::externalFileCoupler::lockName = "OpenFOAM";
// file-scope
@ -46,30 +45,16 @@ Foam::word Foam::externalCoupler::lockName = "OpenFOAM";
static bool checkIsDone(const std::string& lck)
{
std::string content;
std::ifstream is(lck.c_str());
std::ifstream is(lck);
is >> content;
return (content.find("done") != std::string::npos);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
const Foam::fileName& Foam::externalCoupler::baseDir() const
{
return commsDir_;
}
Foam::fileName Foam::externalCoupler::lockFile() const
{
return resolveFile(lockName + ".lock");
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::externalCoupler::externalCoupler()
Foam::externalFileCoupler::externalFileCoupler()
:
runState_(NONE),
commsDir_("$FOAM_CASE/comms"),
@ -83,22 +68,41 @@ Foam::externalCoupler::externalCoupler()
}
Foam::externalCoupler::externalCoupler(const dictionary& dict)
Foam::externalFileCoupler::externalFileCoupler(const fileName& commsDir)
:
externalCoupler()
runState_(NONE),
commsDir_(commsDir),
waitInterval_(1u),
timeOut_(100u),
slaveFirst_(false),
log(false)
{
commsDir_.expand();
commsDir_.clean();
if (Pstream::master())
{
mkDir(commsDir_);
}
}
Foam::externalFileCoupler::externalFileCoupler(const dictionary& dict)
:
externalFileCoupler()
{
readDict(dict);
if (Pstream::master())
{
mkDir(baseDir());
mkDir(commsDir_);
}
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::externalCoupler::~externalCoupler()
Foam::externalFileCoupler::~externalFileCoupler()
{
shutdown();
}
@ -106,14 +110,21 @@ Foam::externalCoupler::~externalCoupler()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::externalCoupler::readDict(const dictionary& dict)
bool Foam::externalFileCoupler::readDict(const dictionary& dict)
{
// Normally cannot change directory or initialization
// if things have already been initialized
dict.lookup("commsDir") >> commsDir_;
commsDir_.expand();
commsDir_.clean();
slaveFirst_ = dict.lookupOrDefault<bool>("initByExternal", false);
if (!initialized())
{
dict.lookup("commsDir") >> commsDir_;
commsDir_.expand();
commsDir_.clean();
slaveFirst_ = dict.lookupOrDefault<bool>("initByExternal", false);
Info<< type() << ": initialize" << nl
<< " directory: " << commsDir_ << nl
<< " slave-first: " << Switch(slaveFirst_) << endl;
}
waitInterval_ = dict.lookupOrDefault("waitInterval", 1u);
if (!waitInterval_)
@ -130,19 +141,7 @@ bool Foam::externalCoupler::readDict(const dictionary& dict)
}
bool Foam::externalCoupler::initialized() const
{
return runState_ != NONE;
}
bool Foam::externalCoupler::slaveFirst() const
{
return slaveFirst_;
}
void Foam::externalCoupler::useMaster(const bool wait) const
void Foam::externalFileCoupler::useMaster(const bool wait) const
{
const bool wasInit = initialized();
runState_ = MASTER;
@ -162,7 +161,7 @@ void Foam::externalCoupler::useMaster(const bool wait) const
{
Log << type() << ": creating lock file" << endl;
OFstream os(lck);
std::ofstream os(lck);
os << "status=openfoam\n";
os.flush();
}
@ -175,7 +174,7 @@ void Foam::externalCoupler::useMaster(const bool wait) const
}
void Foam::externalCoupler::useSlave(const bool wait) const
void Foam::externalFileCoupler::useSlave(const bool wait) const
{
const bool wasInit = initialized();
runState_ = SLAVE;
@ -200,7 +199,7 @@ void Foam::externalCoupler::useSlave(const bool wait) const
}
bool Foam::externalCoupler::waitForMaster() const
bool Foam::externalFileCoupler::waitForMaster() const
{
if (!initialized())
{
@ -212,7 +211,7 @@ bool Foam::externalCoupler::waitForMaster() const
{
const fileName lck(lockFile());
double prevTime = -1;
double prevTime = 0;
double modTime = 0;
// Wait until file disappears (modTime == 0)
@ -239,7 +238,7 @@ bool Foam::externalCoupler::waitForMaster() const
}
bool Foam::externalCoupler::waitForSlave() const
bool Foam::externalFileCoupler::waitForSlave() const
{
if (!initialized())
{
@ -281,23 +280,38 @@ bool Foam::externalCoupler::waitForSlave() const
}
Foam::fileName Foam::externalCoupler::resolveFile
(
const word& file
) const
{
return fileName(baseDir()/file);
}
void Foam::externalFileCoupler::readDataMaster()
{}
void Foam::externalCoupler::shutdown() const
void Foam::externalFileCoupler::readDataSlave()
{}
void Foam::externalFileCoupler::writeDataMaster() const
{}
void Foam::externalFileCoupler::writeDataSlave() const
{}
void Foam::externalFileCoupler::removeDataMaster() const
{}
void Foam::externalFileCoupler::removeDataSlave() const
{}
void Foam::externalFileCoupler::shutdown() const
{
if (Pstream::master() && runState_ == MASTER && Foam::isDir(commsDir_))
{
const fileName lck(lockFile());
Log << type() << ": lock file status=done" << endl;
OFstream os(lck);
std::ofstream os(lck);
os << "status=done\n";
os.flush();
}

View File

@ -22,7 +22,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::externalCoupler
Foam::externalFileCoupler
Description
Encapsulates the logic for coordinating between OpenFOAM and an
@ -57,13 +57,32 @@ Description
}
\endverbatim
A typical coupling loop would look like this (on the master-side):
\verbatim
initialize - master takes control
write data for slave
use slave, wait for slave
cleanup old data from master
read data from slave
use master
\endverbatim
On the slave-side:
\verbatim
wait for master
read data from master
write data for master
use master
\endverbatim
SourceFiles
externalCoupler.C
externalFileCoupler.C
externalFileCouplerI.H
\*---------------------------------------------------------------------------*/
#ifndef externalCoupler_H
#define externalCoupler_H
#ifndef externalFileCoupler_H
#define externalFileCoupler_H
#include "fileName.H"
#include "dictionary.H"
@ -74,20 +93,26 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class externalCoupler Declaration
Class externalFileCoupler Declaration
\*---------------------------------------------------------------------------*/
class externalCoupler
class externalFileCoupler
{
//- The run state (ie, who is currently in charge)
enum runState
{
NONE, //!< Not initialized
MASTER, //!< The master (OpenFOAM) is in charge
SLAVE, //!< The slave (external program) is in charge
DONE //!< Finished
};
public:
// Public data types
//- The run state (ie, who is currently in charge)
enum runState
{
NONE, //!< Not initialized
MASTER, //!< The master (OpenFOAM) is in charge
SLAVE, //!< The slave (external program) is in charge
DONE //!< Finished
};
private:
// Private data
@ -103,7 +128,7 @@ class externalCoupler
//- Timeout [s] while waiting for the external application
unsigned timeOut_;
//- Flag to indicate values are initialized by external application
//- Flag to indicate values are initialized by external program
bool slaveFirst_;
//- Local logging/verbosity flag
@ -112,22 +137,17 @@ class externalCoupler
// Private Member Functions
//- Return the file path to the base communications directory
const fileName& baseDir() const;
//- Return the file path to the lock file
fileName lockFile() const;
//- Disallow default bitwise copy construc
externalCoupler(const externalCoupler&) = delete;
//- Disallow default bitwise copy construct
externalFileCoupler(const externalFileCoupler&) = delete;
//- Disallow default bitwise assignmen
void operator=(const externalCoupler&) = delete;
void operator=(const externalFileCoupler&) = delete;
public:
//- Runtime type information
TypeName("externalCoupler");
TypeName("externalFileCoupler");
// Static data members
@ -138,48 +158,98 @@ public:
// Constructors
//- Construct null using standard defaults
externalCoupler();
//- Construct using standard defaults.
// Does not create communications directory.
externalFileCoupler();
//- Construct with specified communications directory.
// Creates the communications directory upon construction.
externalFileCoupler(const fileName& commsDir);
//- Construct from dictionary
externalCoupler(const dictionary& dict);
// Creates the communications directory upon construction.
externalFileCoupler(const dictionary& dict);
//- Destructor
virtual ~externalCoupler();
virtual ~externalFileCoupler();
// Member Functions
// Access
// Initialization
//- True if state has been initialized
bool initialized() const;
inline bool initialized() const;
//- External application provides initial values
bool slaveFirst() const;
inline bool slaveFirst() const;
// File locations
//- Return the file path to the base communications directory
inline const fileName& commDirectory() const;
//- Return the file path in the communications directory
inline fileName resolveFile(const word& file) const;
//- Return the file path to the lock file
inline fileName lockFile() const;
// Settings
//- Read communication settings from dictionary
bool readDict(const dictionary& dict);
// Handshaking
//- Create lock file to indicate that OpenFOAM is in charge
// Optionally wait for master as well.
// Optionally wait for master to complete as well.
void useMaster(const bool wait=false) const;
//- Wait for indication that OpenFOAM has supplied output.
// This is when the lock file disappears, or it exists but with
//- Remove lock file to indicate that the external program is in charge
// Optionally wait for slave to complete as well.
void useSlave(const bool wait=false) const;
//- Wait for master to complete.
// This is when the lock file disappears, or exists but has
// "status=done" content.
// \return False if lock file contains "status=done"
bool waitForMaster() const;
//- Remove lock file to indicate that the external program is in charge
// Optionally wait for slave as well.
void useSlave(const bool wait=false) const;
//- Wait for indication that the external program has supplied input.
//- Wait for slave to complete.
// This is when the lock file appears.
// \return False if lock file contains "status=done"
bool waitForSlave() const;
//- Return the file path in the communications directory
fileName resolveFile(const word& file) const;
// File creation, removal
//- Read data files on master (OpenFOAM).
// These data files are normally created by the slave.
virtual void readDataMaster();
//- Read data files on slave (external program).
// These data files are normally created by the master.
virtual void readDataSlave();
//- Write data files from master (OpenFOAM)
virtual void writeDataMaster() const;
//- Write data files from slave (external program)
virtual void writeDataSlave() const;
//- Remove data files written by master (OpenFOAM)
virtual void removeDataMaster() const;
//- Remove data files written by slave (external program)
virtual void removeDataSlave() const;
//- Generate status=done in lock (only when run-state = master)
void shutdown() const;
@ -188,11 +258,6 @@ public:
void removeDirectory() const;
// Edit
//- Read communication settings from dictionary
bool readDict(const dictionary& dict);
};
@ -202,6 +267,10 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "externalFileCouplerI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::externalFileCoupler::initialized() const
{
return runState_ != NONE;
}
inline bool Foam::externalFileCoupler::slaveFirst() const
{
return slaveFirst_;
}
inline const Foam::fileName& Foam::externalFileCoupler::commDirectory() const
{
return commsDir_;
}
inline Foam::fileName Foam::externalFileCoupler::resolveFile
(
const word& file
) const
{
return fileName(commDirectory()/file);
}
inline Foam::fileName Foam::externalFileCoupler::lockFile() const
{
return resolveFile(lockName + ".lock");
}
// ************************************************************************* //

View File

@ -50,20 +50,6 @@ namespace functionObjects
}
}
const Foam::Enum
<
Foam::functionObjects::externalCoupled::stateEnd
>
Foam::functionObjects::externalCoupled::stateEndNames_
{
{ stateEnd::REMOVE, "remove" },
{ stateEnd::DONE, "done" }
// 'IGNORE' is internal use only and thus without a name
};
Foam::word Foam::functionObjects::externalCoupled::lockName = "OpenFOAM";
Foam::string Foam::functionObjects::externalCoupled::patchKey = "// Patch:";
@ -99,15 +85,6 @@ static void writeList(Ostream& os, const string& header, const UList<T>& L)
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::fileName Foam::functionObjects::externalCoupled::baseDir() const
{
fileName result(commsDir_);
result.clean();
return result;
}
Foam::fileName Foam::functionObjects::externalCoupled::groupDir
(
const fileName& commsDir,
@ -127,171 +104,6 @@ Foam::fileName Foam::functionObjects::externalCoupled::groupDir
}
Foam::fileName Foam::functionObjects::externalCoupled::lockFile() const
{
return fileName(baseDir()/(lockName + ".lock"));
}
void Foam::functionObjects::externalCoupled::useMaster() const
{
if (Pstream::master())
{
const fileName lck(lockFile());
// Only create lock file if it doesn't already exist
if (!Foam::isFile(lck))
{
Log << type() << ": creating lock file" << endl;
OFstream os(lck);
os << "status=openfoam\n";
os.flush();
}
}
}
void Foam::functionObjects::externalCoupled::useSlave() const
{
if (Pstream::master())
{
Log << type() << ": removing lock file" << endl;
Foam::rm(lockFile());
}
}
void Foam::functionObjects::externalCoupled::cleanup() const
{
if (Pstream::master())
{
const fileName lck(lockFile());
switch (stateEnd_)
{
case REMOVE:
{
Log << type() << ": removing lock file" << endl;
Foam::rm(lck);
break;
}
case DONE:
{
Log << type() << ": lock file status=done" << endl;
OFstream os(lck);
os << "status=done\n";
os.flush();
break;
}
case IGNORE:
break;
}
stateEnd_ = IGNORE; // Avoid re-triggering in destructor
}
}
void Foam::functionObjects::externalCoupled::removeDataSlave() const
{
if (!Pstream::master())
{
return;
}
Log << type() << ": removing data files written by slave" << nl;
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
forAll(groupReadFields_[groupi], fieldi)
{
const word& fieldName = groupReadFields_[groupi][fieldi];
rm
(
groupDir(commsDir_, compName, groupName)
/ fieldName + ".in"
);
}
}
}
}
void Foam::functionObjects::externalCoupled::removeDataMaster() const
{
if (!Pstream::master())
{
return;
}
Log << type() << ": removing data files written by master" << nl;
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
forAll(groupReadFields_[groupi], fieldi)
{
const word& fieldName = groupReadFields_[groupi][fieldi];
rm
(
groupDir(commsDir_, compName, groupName)
/ fieldName + ".out"
);
}
}
}
}
void Foam::functionObjects::externalCoupled::waitForSlave() const
{
bool waiting = true;
if (Pstream::master())
{
const fileName lck(lockFile());
unsigned totalTime = 0;
Log << type() << ": beginning wait for lock file " << lck << nl;
while ((waiting = !Foam::isFile(lck)) == true)
{
sleep(waitInterval_);
totalTime += waitInterval_;
if (timeOut_ && totalTime > timeOut_)
{
FatalErrorInFunction
<< "Wait time exceeded timeout of " << timeOut_
<< " s" << abort(FatalError);
}
Log << type() << ": wait time = " << totalTime << endl;
}
Log << type() << ": found lock file " << lck << endl;
}
// MPI barrier
Pstream::scatter(waiting);
}
void Foam::functionObjects::externalCoupled::readColumns
(
const label nRows,
@ -465,21 +277,19 @@ void Foam::functionObjects::externalCoupled::writeGeometry
labelList pointToGlobal;
labelList uniquePointIDs;
forAll(meshes, meshi)
for (const fvMesh& mesh : meshes)
{
const fvMesh& mesh = meshes[meshi];
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
List<wordRe>{groupName}
).sortedToc()
);
forAll(patchIDs, i)
for (const label patchi : patchIDs)
{
const polyPatch& p = mesh.boundaryMesh()[patchIDs[i]];
const polyPatch& p = mesh.boundaryMesh()[patchi];
mesh.globalData().mergePoints
(
@ -592,207 +402,62 @@ void Foam::functionObjects::externalCoupled::checkOrder
}
void Foam::functionObjects::externalCoupled::readData()
void Foam::functionObjects::externalCoupled::initCoupling()
{
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const wordList& regionNames = regionGroupRegions_[regioni];
// Get the meshes for the region-group
UPtrList<const fvMesh> meshes(regionNames.size());
forAll(regionNames, j)
{
const word& regionName = regionNames[j];
meshes.set(j, &time_.lookupObject<fvMesh>(regionName));
}
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupReadFields_[groupi];
forAll(fieldNames, fieldi)
{
const word& fieldName = fieldNames[fieldi];
const bool ok =
(
readData<scalar>
(
meshes,
groupName,
fieldName
)
|| readData<vector>
(
meshes,
groupName,
fieldName
)
|| readData<sphericalTensor>
(
meshes,
groupName,
fieldName
)
|| readData<symmTensor>
(
meshes,
groupName,
fieldName
)
|| readData<tensor>
(
meshes,
groupName,
fieldName
)
);
if (!ok)
{
WarningInFunction
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
}
}
}
void Foam::functionObjects::externalCoupled::writeData() const
{
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const wordList& regionNames = regionGroupRegions_[regioni];
// Get the meshes for the region-group
UPtrList<const fvMesh> meshes(regionNames.size());
forAll(regionNames, j)
{
const word& regionName = regionNames[j];
meshes.set(j, &time_.lookupObject<fvMesh>(regionName));
}
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupWriteFields_[groupi];
forAll(fieldNames, fieldi)
{
const word& fieldName = fieldNames[fieldi];
const bool ok =
(
writeData<scalar>
(
meshes,
groupName,
fieldName
)
|| writeData<vector>
(
meshes,
groupName,
fieldName
)
|| writeData<sphericalTensor>
(
meshes,
groupName,
fieldName
)
|| writeData<symmTensor>
(
meshes,
groupName,
fieldName
)
|| writeData<tensor>
(
meshes,
groupName,
fieldName
)
);
if (!ok)
{
WarningInFunction
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
}
}
}
void Foam::functionObjects::externalCoupled::initialise()
{
if (initialised_)
if (initialisedCoupling_)
{
return;
}
// Write the geometry if not already there
forAll(regionGroupRegions_, i)
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[i];
const wordList& regionNames = regionGroupRegions_[i];
const word& compName = regionGroupNames_[regioni];
const wordList& regionNames = regionGroupRegions_[regioni];
// Get the meshes for the region-group
UPtrList<const fvMesh> meshes(regionNames.size());
forAll(regionNames, j)
forAll(regionNames, regi)
{
const word& regionName = regionNames[j];
meshes.set(j, &time_.lookupObject<fvMesh>(regionName));
const word& regionName = regionNames[regi];
meshes.set(regi, &time_.lookupObject<fvMesh>(regionName));
}
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
for (const label groupi : groups)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
bool exists = false;
bool geomExists = false;
if (Pstream::master())
{
fileName dir(groupDir(commsDir_, compName, groupName));
fileName dir(groupDir(commDirectory(), compName, groupName));
exists =
geomExists =
isFile(dir/"patchPoints")
|| isFile(dir/"patchFaces");
}
if (!returnReduce(exists, orOp<bool>()))
Pstream::scatter(geomExists);
if (!geomExists)
{
writeGeometry(meshes, commsDir_, groupName);
writeGeometry(meshes, commDirectory(), groupName);
}
}
}
if (slaveFirst_)
if (slaveFirst())
{
// Wait for initial data to be made available
waitForSlave();
// Read data passed back from external source
readData();
readDataMaster();
}
initialised_ = true;
initialisedCoupling_ = true;
}
@ -806,18 +471,13 @@ Foam::functionObjects::externalCoupled::externalCoupled
)
:
functionObject(name),
externalFileCoupler(),
time_(runTime),
stateEnd_(REMOVE),
initialised_(false)
initialisedCoupling_(false)
{
read(dict);
if (Pstream::master())
{
mkDir(baseDir());
}
if (!slaveFirst_)
if (!slaveFirst())
{
useMaster();
}
@ -827,22 +487,20 @@ Foam::functionObjects::externalCoupled::externalCoupled
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::externalCoupled::~externalCoupled()
{
cleanup();
}
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::externalCoupled::execute()
{
if (!initialised_ || time_.timeIndex() % calcFrequency_ == 0)
if (!initialisedCoupling_ || time_.timeIndex() % calcFrequency_ == 0)
{
// Initialise the coupling
initialise();
initCoupling();
// Write data for external source
writeData();
writeDataMaster();
// Signal external source to execute (by removing lock file)
// - Wait for slave to provide data
@ -855,7 +513,7 @@ bool Foam::functionObjects::externalCoupled::execute()
removeDataMaster();
// Read data passed back from external source
readData();
readDataMaster();
// Signal external source to wait (by creating the lock file)
useMaster();
@ -876,7 +534,7 @@ bool Foam::functionObjects::externalCoupled::end()
// Remove old data files
removeDataMaster();
removeDataSlave();
cleanup();
shutdown();
return true;
}
@ -885,33 +543,10 @@ bool Foam::functionObjects::externalCoupled::end()
bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
{
functionObject::read(dict);
// NB: Cannot change directory or initialization
// if things have already been initialized
if (!initialised_)
{
dict.lookup("commsDir") >> commsDir_;
commsDir_.expand();
commsDir_.clean();
slaveFirst_ = readBool(dict.lookup("initByExternal"));
// slaveFirst_ = dict.lookupOrDefault<bool>("initByExternal", false);
}
externalFileCoupler::readDict(dict);
calcFrequency_ = dict.lookupOrDefault("calcFrequency", 1);
waitInterval_ = dict.lookupOrDefault("waitInterval", 1u);
if (!waitInterval_)
{
// Enforce non-zero sleep
waitInterval_ = 1u;
}
timeOut_ = dict.lookupOrDefault("timeOut", 100*waitInterval_);
stateEnd_ =
stateEndNames_.lookupOrDefault("stateEnd", dict, stateEnd::DONE);
// Get names of all fvMeshes (and derived types)
wordList allRegionNames(time_.lookupClass<fvMesh>().sortedToc());
@ -960,7 +595,7 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
regionToGroups_.insert
(
regionGroupNames_.last(),
labelList(1, nGroups)
labelList{nGroups}
);
}
groupNames_.append(groupName);
@ -971,16 +606,12 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
Info<< type() << ": Communicating with regions:" << endl;
forAll(regionGroupNames_, rgi)
for (const word& compName : regionGroupNames_)
{
//const wordList& regionNames = regionGroupRegions_[rgi];
const word& compName = regionGroupNames_[rgi];
Info<< "Region: " << compName << endl << incrIndent;
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
for (const label groupi : groups)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
Info<< indent << "patchGroup: " << groupName << "\t"
@ -1003,17 +634,15 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
// should already be written - but just make sure
if (Pstream::master())
{
forAll(regionGroupNames_, rgi)
for (const word& compName : regionGroupNames_)
{
const word& compName = regionGroupNames_[rgi];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
for (const label groupi : groups)
{
label groupi = groups[i];
const wordRe& groupName = groupNames_[groupi];
fileName dir(groupDir(commsDir_, compName, groupName));
fileName dir(groupDir(commDirectory(), compName, groupName));
if (!isDir(dir))
{
Log << type() << ": creating communications directory "
@ -1028,6 +657,156 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
}
void Foam::functionObjects::externalCoupled::readDataMaster()
{
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const wordList& regionNames = regionGroupRegions_[regioni];
// Get the meshes for the region-group
UPtrList<const fvMesh> meshes(regionNames.size());
forAll(regionNames, j)
{
const word& regionName = regionNames[j];
meshes.set(j, &time_.lookupObject<fvMesh>(regionName));
}
const labelList& groups = regionToGroups_[compName];
for (const label groupi : groups)
{
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupReadFields_[groupi];
for (const word& fieldName : fieldNames)
{
const bool ok =
(
readData<scalar>(meshes, groupName, fieldName)
|| readData<vector>(meshes, groupName, fieldName)
|| readData<sphericalTensor>(meshes, groupName, fieldName)
|| readData<symmTensor>(meshes, groupName, fieldName)
|| readData<tensor>(meshes, groupName, fieldName)
);
if (!ok)
{
WarningInFunction
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
}
}
}
void Foam::functionObjects::externalCoupled::writeDataMaster() const
{
forAll(regionGroupNames_, regioni)
{
const word& compName = regionGroupNames_[regioni];
const wordList& regionNames = regionGroupRegions_[regioni];
// Get the meshes for the region-group
UPtrList<const fvMesh> meshes(regionNames.size());
forAll(regionNames, j)
{
const word& regionName = regionNames[j];
meshes.set(j, &time_.lookupObject<fvMesh>(regionName));
}
const labelList& groups = regionToGroups_[compName];
for (const label groupi : groups)
{
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupWriteFields_[groupi];
for (const word& fieldName : fieldNames)
{
const bool ok =
(
writeData<scalar>(meshes, groupName, fieldName)
|| writeData<vector>(meshes, groupName, fieldName)
|| writeData<sphericalTensor>(meshes, groupName, fieldName)
|| writeData<symmTensor>(meshes, groupName, fieldName)
|| writeData<tensor>(meshes, groupName, fieldName)
);
if (!ok)
{
WarningInFunction
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
}
}
}
void Foam::functionObjects::externalCoupled::removeDataMaster() const
{
if (!Pstream::master())
{
return;
}
Log << type() << ": removing data files written by master" << nl;
for (const word& compName : regionGroupNames_)
{
const labelList& groups = regionToGroups_[compName];
for (const label groupi : groups)
{
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupReadFields_[groupi];
for (const word& fieldName : fieldNames)
{
Foam::rm
(
groupDir(commDirectory(), compName, groupName)
/ fieldName + ".out"
);
}
}
}
}
void Foam::functionObjects::externalCoupled::removeDataSlave() const
{
if (!Pstream::master())
{
return;
}
Log << type() << ": removing data files written by slave" << nl;
for (const word& compName : regionGroupNames_)
{
const labelList& groups = regionToGroups_[compName];
for (const label groupi : groups)
{
const wordRe& groupName = groupNames_[groupi];
const wordList& fieldNames = groupReadFields_[groupi];
for (const word& fieldName : fieldNames)
{
Foam::rm
(
groupDir(commDirectory(), compName, groupName)
/ fieldName + ".in"
);
}
}
}
}
bool Foam::functionObjects::externalCoupled::write()
{
return true;

View File

@ -42,7 +42,7 @@ Description
where the actual entries depend on the bc type:
- mixed: value, snGrad, refValue, refGrad, valueFraction
- externalCoupledMixed: output of writeData
- externalCoupledMixed: output of writeDataMaster
- other: value, snGrad
These text files are located in a user specified communications directory
@ -146,6 +146,7 @@ SourceFiles
#define functionObjects_externalCoupled_H
#include "functionObject.H"
#include "externalFileCoupler.H"
#include "DynamicList.H"
#include "wordReList.H"
#include "scalarField.H"
@ -171,7 +172,8 @@ namespace functionObjects
class externalCoupled
:
public functionObject
public functionObject,
public externalFileCoupler
{
public:
@ -190,30 +192,14 @@ private:
//- State end names (NB, only selectable values itemized)
static const Enum<stateEnd> stateEndNames_;
// Private data
//- Reference to the time database
const Time& time_;
//- Path to communications directory
fileName commsDir_;
//- Interval time between checking for return data [s]
unsigned waitInterval_;
//- Time out time [s]
unsigned timeOut_;
//- Calculation frequency
label calcFrequency_;
//- Flag to indicate values are initialised by external application
bool slaveFirst_;
//- Lockfile state on termination
mutable stateEnd stateEnd_;
//- Names of (composite) regions
DynamicList<word> regionGroupNames_;
@ -232,8 +218,8 @@ private:
// Per group the names of the fields to write
DynamicList<wordList> groupWriteFields_;
//- Initialised flag
bool initialised_;
//- Initialised coupling
bool initialisedCoupling_;
// Private Member Functions
@ -246,32 +232,6 @@ private:
const wordRe& groupName
);
//- Return the file path to the base communications directory
fileName baseDir() const;
//- Return the file path to the lock file
fileName lockFile() const;
//- Create lock file to indicate that OpenFOAM is in charge
void useMaster() const;
//- Remove lock file to indicate that the external program is in charge
void useSlave() const;
//- Remove lock file or status=done in lock.
void cleanup() const;
//- Remove files written by OpenFOAM
void removeDataMaster() const;
//- Remove files written by external code
void removeDataSlave() const;
//- Wait for indication that the external program has supplied input
// (ie, for the lock file to reappear).
void waitForSlave() const;
//- Read data for a single region, single field
template<class Type>
@ -281,8 +241,6 @@ private:
const wordRe& groupName,
const word& fieldName
);
//- Read data for all regions, all fields
void readData();
//- Write data for a single region, single field
template<class Type>
@ -293,10 +251,7 @@ private:
const word& fieldName
) const;
//- Write data for all regions, all fields
void writeData() const;
void initialise();
void initCoupling();
//- Read (and distribute) scalar columns from stream. Every processor
// gets nRows (= patch size) of these. Note: could make its argument
@ -339,12 +294,12 @@ public:
//- Runtime type information
TypeName("externalCoupled");
//- Name of lock file (normally 'OpenFOAM.lock')
static word lockName;
//- Name of patch key, e.g. '// Patch:' when looking for start of patch data
static string patchKey;
//- Inherited variable for logging
using functionObject::log;
// Constructors
@ -378,6 +333,21 @@ public:
virtual bool write();
// File creation, removal
//- Write data files (all regions, all fields) from master (OpenFOAM)
virtual void writeDataMaster() const;
//- Read data files (all regions, all fields) on master (OpenFOAM)
virtual void readDataMaster();
//- Remove data files written by master (OpenFOAM)
virtual void removeDataMaster() const;
//- Remove data files written by slave (external code)
virtual void removeDataSlave() const;
// Other
//- Create single name by appending words (in sorted order),

View File

@ -62,7 +62,7 @@ bool Foam::functionObjects::externalCoupled::readData
{
const fileName transferFile
(
groupDir(commsDir_, compositeName(regionNames), groupName)
groupDir(commDirectory(), compositeName(regionNames), groupName)
/ fieldName + ".in"
);
@ -81,46 +81,40 @@ bool Foam::functionObjects::externalCoupled::readData
label nFound = 0;
forAll(meshes, i)
for (const fvMesh& mesh : meshes)
{
const fvMesh& mesh = meshes[i];
const volFieldType* vfptr =
mesh.lookupObjectPtr<volFieldType>(fieldName);
if (!mesh.foundObject<volFieldType>(fieldName))
if (!vfptr)
{
continue;
}
nFound++;
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::Boundary& bf = cvf.boundaryField();
typename volFieldType::Boundary& bf =
const_cast<volFieldType*>(vfptr)->boundaryFieldRef();
// Get the patches
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
List<wordRe>{groupName}
).sortedToc()
);
// Handle column-wise reading of patch data. Supports most easy types
forAll(patchIDs, i)
for (const label patchi : patchIDs)
{
label patchi = patchIDs[i];
if (isA<patchFieldType>(bf[patchi]))
{
// Explicit handling of externalCoupledMixed bcs - they
// have specialised reading routines.
patchFieldType& pf = const_cast<patchFieldType&>
patchFieldType& pf = refCast<patchFieldType>
(
refCast<const patchFieldType>
(
bf[patchi]
)
bf[patchi]
);
// Read from master into local stream
@ -141,6 +135,11 @@ bool Foam::functionObjects::externalCoupled::readData
}
else if (isA<mixedFvPatchField<Type>>(bf[patchi]))
{
mixedFvPatchField<Type>& pf = refCast<mixedFvPatchField<Type>>
(
bf[patchi]
);
// Read columns from file for
// value, snGrad, refValue, refGrad, valueFraction
List<scalarField> data;
@ -152,15 +151,6 @@ bool Foam::functionObjects::externalCoupled::readData
data
);
mixedFvPatchField<Type>& pf =
const_cast<mixedFvPatchField<Type>&>
(
refCast<const mixedFvPatchField<Type>>
(
bf[patchi]
)
);
// Transfer read data to bc.
// Skip value, snGrad
direction columni = 2*pTraits<Type>::nComponents;
@ -193,6 +183,9 @@ bool Foam::functionObjects::externalCoupled::readData
}
else if (isA<fixedGradientFvPatchField<Type>>(bf[patchi]))
{
fixedGradientFvPatchField<Type>& pf =
refCast<fixedGradientFvPatchField<Type>>(bf[patchi]);
// Read columns for value and gradient
List<scalarField> data;
readColumns
@ -203,15 +196,6 @@ bool Foam::functionObjects::externalCoupled::readData
data
);
fixedGradientFvPatchField<Type>& pf =
const_cast<fixedGradientFvPatchField<Type>&>
(
refCast<const fixedGradientFvPatchField<Type>>
(
bf[patchi]
)
);
// Transfer gradient to bc
Field<Type>& gradient = pf.gradient();
for
@ -234,6 +218,9 @@ bool Foam::functionObjects::externalCoupled::readData
}
else if (isA<fixedValueFvPatchField<Type>>(bf[patchi]))
{
fixedValueFvPatchField<Type>& pf =
refCast<fixedValueFvPatchField<Type>>(bf[patchi]);
// Read columns for value only
List<scalarField> data;
readColumns
@ -256,15 +243,6 @@ bool Foam::functionObjects::externalCoupled::readData
value.replace(cmpt, data[cmpt]);
}
fixedValueFvPatchField<Type>& pf =
const_cast<fixedValueFvPatchField<Type>&>
(
refCast<const fixedValueFvPatchField<Type>>
(
bf[patchi]
)
);
pf == value;
// Update the value from the read coefficicient. Bypass any
@ -280,7 +258,7 @@ bool Foam::functionObjects::externalCoupled::readData
<< exit(FatalError);
}
initialised_ = true;
initialisedCoupling_ = true;
}
}
@ -357,7 +335,7 @@ bool Foam::functionObjects::externalCoupled::writeData
{
const fileName transferFile
(
groupDir(commsDir_, compositeName(regionNames), groupName)
groupDir(commDirectory(), compositeName(regionNames), groupName)
/ fieldName + ".out"
);
@ -379,35 +357,32 @@ bool Foam::functionObjects::externalCoupled::writeData
label nFound = 0;
forAll(meshes, i)
for (const fvMesh& mesh : meshes)
{
const fvMesh& mesh = meshes[i];
const volFieldType* vfptr =
mesh.lookupObjectPtr<volFieldType>(fieldName);
if (!mesh.foundObject<volFieldType>(fieldName))
if (!vfptr)
{
continue;
}
nFound++;
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::Boundary& bf = cvf.boundaryField();
const typename volFieldType::Boundary& bf =
vfptr->boundaryField();
// Get the patches
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
List<wordRe>{groupName}
).sortedToc()
);
// Handle column-wise writing of patch data. Supports most easy types
forAll(patchIDs, i)
for (const label patchi : patchIDs)
{
label patchi = patchIDs[i];
const globalIndex globalFaces(bf[patchi].size());
if (isA<patchFieldType>(bf[patchi]))

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2016 OpenCFD Ltd.
\\/ M anipulation | Copyright (C) 2016-2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -61,19 +61,43 @@ Foam::functionObjects::abort::actionNames_
};
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
void Foam::functionObjects::abort::removeFile() const
// file-scope
// Long description for the action name
namespace Foam
{
bool hasAbort = isFile(abortFile_);
reduce(hasAbort, orOp<bool>());
if (hasAbort && Pstream::master())
static std::string longDescription(const Time::stopAtControls ctrl)
{
switch (ctrl)
{
// Cleanup ABORT file (on master only)
rm(abortFile_);
case Foam::Time::saNoWriteNow :
{
return "stop without writing data";
break;
}
case Time::saWriteNow :
{
return "stop and write data";
break;
}
case Time::saNextWrite :
{
return "stop after next data write";
break;
}
default:
{
// Invalid choices already filtered out by Enum
return "abort";
break;
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -88,13 +112,17 @@ Foam::functionObjects::abort::abort
functionObject(name),
time_(runTime),
abortFile_("$FOAM_CASE/" + name),
action_(Time::stopAtControls::saNextWrite)
action_(Time::stopAtControls::saNextWrite),
triggered_(false)
{
abortFile_.expand();
read(dict);
// Remove any old files from previous runs
removeFile();
// Cleanup old files from previous runs
if (Pstream::master())
{
Foam::rm(abortFile_);
}
}
@ -110,6 +138,13 @@ bool Foam::functionObjects::abort::read(const dictionary& dict)
{
functionObject::read(dict);
if (dict.readIfPresent("file", abortFile_))
{
abortFile_.expand();
}
const auto oldAction = action_;
action_ = actionNames_.lookupOrDefault
(
"action",
@ -117,64 +152,42 @@ bool Foam::functionObjects::abort::read(const dictionary& dict)
Time::stopAtControls::saNextWrite
);
if (dict.readIfPresent("file", abortFile_))
// User can change action and re-trigger the abort.
// eg, they had nextWrite, but actually wanted writeNow.
if (oldAction != action_)
{
abortFile_.expand();
triggered_ = false;
}
Info<< type() << " activated ("
<< longDescription(action_).c_str() <<")" << nl
<< " File: " << abortFile_ << endl;
return true;
}
bool Foam::functionObjects::abort::execute()
{
bool hasAbort = isFile(abortFile_);
reduce(hasAbort, orOp<bool>());
if (hasAbort)
// If it has been triggered (eg, nextWrite) don't need to check it again
if (!triggered_)
{
switch (action_)
bool hasAbort = (Pstream::master() && isFile(abortFile_));
Pstream::scatter(hasAbort);
if (hasAbort)
{
case Time::saNoWriteNow :
triggered_ = time_.stopAt(action_);
if (triggered_)
{
if (time_.stopAt(action_))
{
Info<< "USER REQUESTED ABORT (timeIndex="
<< time_.timeIndex()
<< "): stop without writing data"
<< endl;
}
break;
Info<< "USER REQUESTED ABORT (timeIndex="
<< time_.timeIndex()
<< "): " << longDescription(action_).c_str()
<< endl;
}
case Time::saWriteNow :
{
if (time_.stopAt(action_))
{
Info<< "USER REQUESTED ABORT (timeIndex="
<< time_.timeIndex()
<< "): stop+write data"
<< endl;
}
break;
}
case Time::saNextWrite :
{
if (time_.stopAt(action_))
{
Info<< "USER REQUESTED ABORT (timeIndex="
<< time_.timeIndex()
<< "): stop after next data write"
<< endl;
}
break;
}
default:
{
// Invalid choices already filtered out by Enum
}
Pstream::scatter(triggered_);
}
}
@ -190,7 +203,12 @@ bool Foam::functionObjects::abort::write()
bool Foam::functionObjects::abort::end()
{
removeFile();
// Cleanup ABORT file
if (Pstream::master())
{
Foam::rm(abortFile_);
}
return true;
}

View File

@ -3,7 +3,7 @@
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ M anipulation |
\\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,12 +30,21 @@ Group
Description
Watches for presence of the named file in the $FOAM_CASE directory
and aborts the calculation if it is present.
The presence of the abort file is only checked on the master process.
Currently the following action types are supported:
- noWriteNow
- writeNow
- nextWrite
\heading Function object usage
\table
Property | Description | Required | Default value
type | Type name: abort | yes |
file | The abort filename | no | $FOAM_CASE/name
action | Abort action | no | nextWrite
\endtable
SourceFiles
abort.C
@ -55,7 +64,7 @@ namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class abort Declaration
Class abort Declaration
\*---------------------------------------------------------------------------*/
class abort
@ -76,12 +85,12 @@ class abort
//- The type of action
Time::stopAtControls action_;
//- Only trigger action once
bool triggered_;
// Private Member Functions
//- Remove abort file.
void removeFile() const;
//- Disallow default bitwise copy construct
abort(const abort&) = delete;
@ -102,7 +111,7 @@ public:
(
const word& name,
const Time& runTime,
const dictionary&
const dictionary& dict
);
@ -115,13 +124,13 @@ public:
//- Read the dictionary settings
virtual bool read(const dictionary& dict);
//- Execute, check existence of abort file and take action
//- Check existence of abort file and take action
virtual bool execute();
//- Execute, check existence of abort file and take action
//- No-op
virtual bool write();
//- Execute at the final time-loop, used for cleanup
//- Remove abort file after the final time-loop.
virtual bool end();
};

View File

@ -1,5 +1,3 @@
externalCoupler.C
lumpedPointMovement.C
lumpedPointMovementWriter.C
lumpedPointState.C

View File

@ -50,7 +50,7 @@ SourceFiles
#include "IOobject.H"
#include "tmp.H"
#include "faceZoneMeshFwd.H"
#include "externalCoupler.H"
#include "externalFileCoupler.H"
#include "lumpedPointState.H"
#include "boundBox.H"
#include "Enum.H"
@ -120,7 +120,7 @@ private:
dictionary forcesDict_;
//- Communication control
externalCoupler coupler_;
externalFileCoupler coupler_;
//- File io
word inputName_;
@ -223,10 +223,10 @@ public:
//- Communication control
inline const externalCoupler& coupler() const;
inline const externalFileCoupler& coupler() const;
//- Communication control
inline externalCoupler& coupler();
inline externalFileCoupler& coupler();
//- The initial state (positions/rotations)
inline const lumpedPointState& state0() const;

View File

@ -83,13 +83,14 @@ Foam::lumpedPointMovement::threshold(const point& position) const
}
inline const Foam::externalCoupler& Foam::lumpedPointMovement::coupler() const
inline const Foam::externalFileCoupler&
Foam::lumpedPointMovement::coupler() const
{
return coupler_;
}
inline Foam::externalCoupler& Foam::lumpedPointMovement::coupler()
inline Foam::externalFileCoupler& Foam::lumpedPointMovement::coupler()
{
return coupler_;
}

View File

@ -0,0 +1,13 @@
// OpenFOAM dictionary -*- C++ -*-
ABORT
{
type abort;
libs ("libutilityFunctionObjects.so");
//file "$FOAM_CASE/ABORT"; // default name
// action writeNow;
action nextWrite;
}
// ************************************************************************* //

View File

@ -59,6 +59,7 @@ writeInterval 100;
functions
{
#include "abort"
#include "scalarTransport"
#include "sampling"
}

View File

@ -6,6 +6,9 @@ cd ${0%/*} || exit 1 # Run from this directory
./Allrun.pre
# Remove lock file on interrupt
trap '\rm -f comms/OpenFOAM.lock 2>/dev/null' INT
#-- Run on single processor
#runApplication $(getApplication) &
# Simulated external solver

View File

@ -14,12 +14,11 @@ set -u
echo "Executing dummy external solver"
commsDir="comms"
regionGroupName="heater_topAir"
patchGroupName="coupleGroup"
patchDir="heater_topAir/coupleGroup"
fieldName="T"
lockFile="${commsDir}/OpenFOAM.lock"
dataFile="${commsDir}/${regionGroupName}/${patchGroupName}/${fieldName}"
dataFile="${commsDir}/${patchDir}/${fieldName}"
waitSec=5
timeOut=100
nSteps=1000 # maximum number of time steps. Note: should be more than
@ -27,7 +26,6 @@ nSteps=1000 # maximum number of time steps. Note: should be more than
refGrad=0
valueFraction=1
# Remove any old junk
\rm -f $lockFile 2>/dev/null
@ -36,36 +34,53 @@ log()
echo "External: $@"
}
init()
# Create lock file to pass control to OpenFOAM
useMaster()
{
log "init - creating ${dataFile}.in"
# Hard-coded for patch of size 8 (heater/minY)
n1=8
refValue1=500
touch "${dataFile}.in"
log "init - adding $n1 data elements with refValue $refValue1"
for i in $(seq 1 $n1); do
echo "$refValue1 $refGrad $valueFraction" >> "${dataFile}.in"
done
# Hard-coded for patch of size 40 (topAir/minX)
n2=40
refValue2=300
log "init - adding $n2 data elements with refValue $refValue2"
for i in $(seq 1 $n2); do
echo "$refValue2 $refGrad $valueFraction" >> "${dataFile}.in"
done
# Create lock file to pass control to OpenFOAM
touch ${lockFile}
log "creating lock file '${lockFile}'"
echo "status=openfoam" >| ${lockFile}
}
# create the comms directory
mkdir -p ${commsDir}/${regionGroupName}/${patchGroupName}
init()
{
log "init - creating ${dataFile}.in"
cat /dev/null >| "${dataFile}.in"
# Tutorial case uses 'initByExternalOption', so we must provide initial values
# Hard-coded for patch of size 8 (heater/minY)
local n1=8
local refValue1=500
log "init - adding $n1 data elements with refValue $refValue1"
for i in $(seq 1 $n1)
do
echo "$refValue1 $refGrad $valueFraction"
done >> "${dataFile}.in"
# Hard-coded for patch of size 40 (topAir/minX)
local n2=40
local refValue2=300
log "init - adding $n2 data elements with refValue $refValue2"
for i in $(seq 1 $n2)
do
echo "$refValue2 $refGrad $valueFraction"
done >> "${dataFile}.in"
# Verify line count?
# log "init ($(wc -l ${dataFile}.in))"
# Give time for T.in file to flush
sleep 1
useMaster
}
# Create the comms directory
mkdir -p ${commsDir}/${patchDir}
# Tutorial case uses 'initByExternal' option, so we must provide initial values
init
@ -108,8 +123,7 @@ do
awk '{if( $1 != "#" ){print $1+1 " 0 1"}}' \
${dataFile}.out >| ${dataFile}.in
log "creating lock file '${lockFile}'"
touch ${lockFile}
useMaster
fi
done

View File

@ -14,9 +14,6 @@ externalCoupled
// Does external process start first
initByExternal true;
// Cleanup behaviour on termination (remove|done)
stateEnd done;
// Additional output
log true;