ENH: refactor and combine externalFileCoupler (issue #529)

This commit is contained in:
Mark Olesen
2017-07-17 12:54:02 +02:00
parent e045d6c03b
commit 7a408c713b
19 changed files with 578 additions and 601 deletions

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,
@ -592,155 +404,9 @@ 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;
}
@ -769,7 +435,7 @@ void Foam::functionObjects::externalCoupled::initialise()
bool exists = false;
if (Pstream::master())
{
fileName dir(groupDir(commsDir_, compName, groupName));
fileName dir(groupDir(commDirectory(), compName, groupName));
exists =
isFile(dir/"patchPoints")
@ -778,21 +444,21 @@ void Foam::functionObjects::externalCoupled::initialise()
if (!returnReduce(exists, orOp<bool>()))
{
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 +472,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 +488,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 +514,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 +535,7 @@ bool Foam::functionObjects::externalCoupled::end()
// Remove old data files
removeDataMaster();
removeDataSlave();
cleanup();
shutdown();
return true;
}
@ -885,33 +544,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());
@ -1013,7 +649,8 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
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 +665,218 @@ 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];
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::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];
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::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(commDirectory(), compName, groupName)
/ fieldName + ".out"
);
}
}
}
}
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(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"
);
@ -280,7 +280,7 @@ bool Foam::functionObjects::externalCoupled::readData
<< exit(FatalError);
}
initialised_ = true;
initialisedCoupling_ = true;
}
}
@ -357,7 +357,7 @@ bool Foam::functionObjects::externalCoupled::writeData
{
const fileName transferFile
(
groupDir(commsDir_, compositeName(regionNames), groupName)
groupDir(commDirectory(), compositeName(regionNames), groupName)
/ fieldName + ".out"
);