Commit 9b66285c authored by Mark Olesen's avatar Mark Olesen
Browse files

Merge remote-tracking branch 'origin/externalCoupled' into develop

- update tutorial and adjust function object for updated infrastructure.
parents 8b4dfe24 54c40e73
......@@ -52,7 +52,55 @@ namespace functionObjects
Foam::word Foam::functionObjects::externalCoupled::lockName = "OpenFOAM";
Foam::string Foam::functionObjects::externalCoupled::patchKey = "# Patch: ";
Foam::string Foam::functionObjects::externalCoupled::patchKey = "// Patch:";
template<>
const char* Foam::NamedEnum
<
Foam::functionObjects::externalCoupled::stateEnd,
2
>::names[] =
{
"remove",
"done"
// The 'IGNORE' enumeration is internal use only and thus has no name
};
const Foam::NamedEnum
<
Foam::functionObjects::externalCoupled::stateEnd,
2
> Foam::functionObjects::externalCoupled::stateEndNames_;
namespace Foam
{
//! \cond fileScope
//- Write list content with size, bracket, content, bracket one-per-line.
// This makes for consistent for parsing, regardless of the list length.
template <class T>
static void writeList(Ostream& os, const string& header, const UList<T>& L)
{
// Header string
os << header.c_str() << nl;
// Write size and start delimiter
os << L.size() << nl
<< token::BEGIN_LIST;
// Write contents
forAll(L, i)
{
os << nl << L[i];
}
// Write end delimiter
os << nl << token::END_LIST << nl << endl;
}
//! \endcond
}
// namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
......@@ -91,7 +139,7 @@ Foam::fileName Foam::functionObjects::externalCoupled::lockFile() const
}
void Foam::functionObjects::externalCoupled::createLockFile() const
void Foam::functionObjects::externalCoupled::useMaster() const
{
if (!Pstream::master())
{
......@@ -107,13 +155,13 @@ void Foam::functionObjects::externalCoupled::createLockFile() const
Log << type() << ": creating lock file" << endl;
OFstream os(fName);
os << "lock file";
os << "status=openfoam\n";
os.flush();
}
}
void Foam::functionObjects::externalCoupled::removeLockFile() const
void Foam::functionObjects::externalCoupled::useSlave() const
{
if (!Pstream::master())
{
......@@ -122,7 +170,37 @@ void Foam::functionObjects::externalCoupled::removeLockFile() const
Log << type() << ": removing lock file" << endl;
rm(lockFile());
Foam::rm(lockFile());
}
void Foam::functionObjects::externalCoupled::cleanup() const
{
if (!Pstream::master())
{
return;
}
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;
}
}
......@@ -192,30 +270,29 @@ void Foam::functionObjects::externalCoupled::removeWriteFiles() const
}
void Foam::functionObjects::externalCoupled::wait() const
void Foam::functionObjects::externalCoupled::waitForSlave() const
{
const fileName fName(lockFile());
label found = 0;
label totalTime = 0;
bool found = false;
Log << type() << ": beginning wait for lock file " << fName << nl;
while (found == 0)
while (!found)
{
if (Pstream::master())
{
if (totalTime > timeOut_)
{
FatalErrorInFunction
<< "Wait time exceeded time out time of " << timeOut_
<< "Wait time exceeded timeout of " << timeOut_
<< " s" << abort(FatalError);
}
IFstream is(fName);
if (is.good())
{
found++;
found = true;
Log << type() << ": found lock file " << fName << endl;
}
......@@ -229,7 +306,7 @@ void Foam::functionObjects::externalCoupled::wait() const
}
// Prevent other procs from racing ahead
reduce(found, sumOp<label>());
reduce(found, orOp<bool>());
}
}
......@@ -384,8 +461,6 @@ void Foam::functionObjects::externalCoupled::writeGeometry
fileName dir(groupDir(commsDir, compositeName(regionNames), groupName));
Info<< typeName << ": writing geometry to " << dir << endl;
autoPtr<OFstream> osPointsPtr;
autoPtr<OFstream> osFacesPtr;
if (Pstream::master())
......@@ -393,124 +468,87 @@ void Foam::functionObjects::externalCoupled::writeGeometry
mkDir(dir);
osPointsPtr.reset(new OFstream(dir/"patchPoints"));
osFacesPtr.reset(new OFstream(dir/"patchFaces"));
osPointsPtr() << "// Group: " << groupName << endl;
osFacesPtr() << "// Group: " << groupName << endl;
Info<< typeName << ": writing geometry to " << dir << endl;
}
// Individual region/patch entries
DynamicList<face> allMeshesFaces;
DynamicField<point> allMeshesPoints;
DynamicList<face> allFaces;
DynamicField<point> allPoints;
labelList pointToGlobal;
labelList uniquePointIDs;
forAll(meshes, meshi)
{
const fvMesh& mesh = meshes[meshi];
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
const labelList patchIDs
(
pbm.patchSet(List<wordRe>(1, groupName)).sortedToc()
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
).sortedToc()
);
// Count faces
label nFaces = 0;
forAll(patchIDs, i)
{
nFaces += pbm[patchIDs[i]].size();
}
// Collect faces
DynamicList<label> allFaceIDs(nFaces);
forAll(patchIDs, i)
{
const polyPatch& p = pbm[patchIDs[i]];
forAll(p, pi)
{
allFaceIDs.append(p.start()+pi);
}
}
// Construct overall patch
indirectPrimitivePatch allPatch
(
IndirectList<face>(mesh.faces(), allFaceIDs),
mesh.points()
);
labelList pointToGlobal;
labelList uniquePointIDs;
mesh.globalData().mergePoints
(
allPatch.meshPoints(),
allPatch.meshPointMap(),
pointToGlobal,
uniquePointIDs
);
label proci = Pstream::myProcNo();
const polyPatch& p = mesh.boundaryMesh()[patchIDs[i]];
List<pointField> collectedPoints(Pstream::nProcs());
collectedPoints[proci] = pointField(mesh.points(), uniquePointIDs);
Pstream::gatherList(collectedPoints);
mesh.globalData().mergePoints
(
p.meshPoints(),
p.meshPointMap(),
pointToGlobal,
uniquePointIDs
);
List<faceList> collectedFaces(Pstream::nProcs());
faceList& patchFaces = collectedFaces[proci];
patchFaces = allPatch.localFaces();
forAll(patchFaces, facei)
{
inplaceRenumber(pointToGlobal, patchFaces[facei]);
}
Pstream::gatherList(collectedFaces);
label proci = Pstream::myProcNo();
if (Pstream::master())
{
// Append and renumber
label nPoints = allMeshesPoints.size();
List<pointField> collectedPoints(Pstream::nProcs());
collectedPoints[proci] = pointField(mesh.points(), uniquePointIDs);
Pstream::gatherList(collectedPoints);
forAll(collectedPoints, proci)
List<faceList> collectedFaces(Pstream::nProcs());
faceList& patchFaces = collectedFaces[proci];
patchFaces = p.localFaces();
forAll(patchFaces, facei)
{
allMeshesPoints.append(collectedPoints[proci]);
inplaceRenumber(pointToGlobal, patchFaces[facei]);
}
face newFace;
forAll(collectedFaces, proci)
Pstream::gatherList(collectedFaces);
if (Pstream::master())
{
const faceList& procFaces = collectedFaces[proci];
allPoints.clear();
allFaces.clear();
forAll(procFaces, facei)
for (label proci=0; proci < Pstream::nProcs(); ++proci)
{
const face& f = procFaces[facei];
newFace.setSize(f.size());
forAll(f, fp)
{
newFace[fp] = f[fp]+nPoints;
}
allMeshesFaces.append(newFace);
allPoints.append(collectedPoints[proci]);
allFaces.append(collectedFaces[proci]);
}
nPoints += collectedPoints[proci].size();
Info<< typeName << ": mesh " << mesh.name()
<< ", patch " << p.name()
<< ": writing " << allPoints.size() << " points to "
<< osPointsPtr().name() << nl
<< typeName << ": mesh " << mesh.name()
<< ", patch " << p.name()
<< ": writing " << allFaces.size() << " faces to "
<< osFacesPtr().name() << endl;
// The entry name (region / patch)
const string entryHeader =
patchKey + ' ' + mesh.name() + ' ' + p.name();
writeList(osPointsPtr(), entryHeader, allPoints);
writeList(osFacesPtr(), entryHeader, allFaces);
}
}
{
Info<< typeName << ": for mesh " << mesh.name()
<< " writing " << allMeshesPoints.size() << " points to "
<< osPointsPtr().name() << endl;
Info<< typeName << ": for mesh " << mesh.name()
<< " writing " << allMeshesFaces.size() << " faces to "
<< osFacesPtr().name() << endl;
}
}
// Write points
if (osPointsPtr.valid())
{
osPointsPtr() << allMeshesPoints << endl;
}
// Write faces
if (osFacesPtr.valid())
{
osFacesPtr() << allMeshesFaces << endl;
}
}
......@@ -532,7 +570,7 @@ Foam::word Foam::functionObjects::externalCoupled::compositeName
{
// For compatibility with single region cases suppress single
// region name
return word("");
return word::null;
}
else
{
......@@ -759,7 +797,7 @@ void Foam::functionObjects::externalCoupled::initialise()
if (initByExternal_)
{
// Wait for initial data to be made available
wait();
waitForSlave();
// Read data passed back from external source
readData();
......@@ -780,7 +818,7 @@ Foam::functionObjects::externalCoupled::externalCoupled
:
functionObject(name),
time_(runTime),
enabled_(true),
stateEnd_(REMOVE),
initialised_(false)
{
read(dict);
......@@ -792,7 +830,7 @@ Foam::functionObjects::externalCoupled::externalCoupled
if (!initByExternal_)
{
createLockFile();
useMaster();
}
}
......@@ -800,7 +838,9 @@ Foam::functionObjects::externalCoupled::externalCoupled
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::externalCoupled::~externalCoupled()
{}
{
cleanup();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
......@@ -815,11 +855,12 @@ bool Foam::functionObjects::externalCoupled::execute()
// Write data for external source
writeData();
// remove lock file, signalling external source to execute
removeLockFile();
// Signal external source to execute (by removing lock file)
// - Wait for slave to provide data
useSlave();
// Wait for response
wait();
waitForSlave();
// Remove old data files from OpenFOAM
removeWriteFiles();
......@@ -827,8 +868,8 @@ bool Foam::functionObjects::externalCoupled::execute()
// Read data passed back from external source
readData();
// create lock file for external source
createLockFile();
// Signal external source to wait (by creating the lock file)
useMaster();
return true;
}
......@@ -846,7 +887,9 @@ bool Foam::functionObjects::externalCoupled::end()
// Remove old data files
removeReadFiles();
removeWriteFiles();
removeLockFile();
cleanup();
stateEnd_ = IGNORE; // Avoid running cleanup() again in destructor
return true;
}
......@@ -856,28 +899,24 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
{
functionObject::read(dict);
dict.readIfPresent("enabled", enabled_);
if (!enabled_)
{
return true;
}
calcFrequency_ = dict.lookupOrDefault("calcFrequency", 1);
dict.lookup("commsDir") >> commsDir_;
commsDir_.expand();
commsDir_.clean();
waitInterval_ = dict.lookupOrDefault("waitInterval", 1);
timeOut_ = dict.lookupOrDefault("timeOut", 100*waitInterval_);
calcFrequency_ = dict.lookupOrDefault("calcFrequency", 1);
waitInterval_ = dict.lookupOrDefault("waitInterval", 1);
timeOut_ = dict.lookupOrDefault("timeOut", 100*waitInterval_);
initByExternal_ = readBool(dict.lookup("initByExternal"));
// initByExternal_ = dict.lookupOrDefault<Switch>("initByExternal", false);
stateEnd_ =
stateEndNames_[dict.lookupOrDefault<word>("stateEnd", "remove")];
// Get names of all fvMeshes (and derived types)
wordList allRegionNames(time_.lookupClass<fvMesh>().sortedToc());
const dictionary& allRegionsDict = dict.subDict("regions");
forAllConstIter(dictionary, allRegionsDict, iter)
{
if (!iter().isDict())
......
......@@ -82,6 +82,7 @@ Usage
log yes;
commsDir "${FOAM_CASE}/comms";
initByExternal yes;
stateEnd remove; // (remove | done)
regions
{
......@@ -113,6 +114,7 @@ Usage
application.
SourceFiles
externalCoupled.C
externalCoupledTemplates.C
\*---------------------------------------------------------------------------*/
......@@ -124,6 +126,7 @@ SourceFiles
#include "DynamicList.H"
#include "wordReList.H"
#include "scalarField.H"
#include "NamedEnum.H"
#include "Switch.H"
#include "UPtrList.H"
......@@ -147,14 +150,29 @@ class externalCoupled
:
public functionObject
{
public:
// Public data types
//- Lockfile state on termination
enum stateEnd
{
REMOVE, //!< Remove lock file on end
DONE, //!< Lock file contains status=done on end
IGNORE //!< Internal use only (for handling cleanup).
};
private:
//- State end names
static const NamedEnum<stateEnd, 2> stateEndNames_;
// Private data
//- Reference to the time database
const Time& time_;
//- Switch for the execution - defaults to 'yes/on'
Switch enabled_;
//- Path to communications directory
fileName commsDir_;
......@@ -170,6 +188,9 @@ class externalCoupled
//- Flag to indicate values are initialised by external application
bool initByExternal_;
//- Lockfile state on termination
stateEnd stateEnd_;
//- Names of (composite) regions
DynamicList<word> regionGroupNames_;
......@@ -208,11 +229,15 @@ class externalCoupled
//- Return the file path to the lock file
fileName lockFile() const;
//- Create lock file
void createLockFile() const;
//- Remove lock file
void removeLockFile() 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 removeWriteFiles() const;
......@@ -220,8 +245,9 @@ class externalCoupled
//- Remove files written by external code
void removeReadFiles() const;
//- Wait for response from external source
void wait() 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
......@@ -290,10 +316,10 @@ public:
//- Runtime type information
TypeName("externalCoupled");
//- Name of lock file
//- Name of lock file (normally 'OpenFOAM.lock')
static word lockName;
//- Name of patch key, e.g. '# Patch:' when looking for start of patch data
//- Name of patch key, e.g. '// Patch:' when looking for start of patch data
static string patchKey;
......@@ -335,7 +361,7 @@ public:
// separated by '_'
static word compositeName(const wordList&);
//- Write geometry for the group/patch
//- Write geometry for the group as region/patch
static void writeGeometry
(
const UPtrList<const fvMesh>& meshes,
......
......@@ -81,8 +81,6 @@ bool Foam::functionObjects::externalCoupled::readData
label nFound = 0;
forAll(meshes, i)
{
const fvMesh& mesh = meshes[i];
......
......@@ -15,6 +15,12 @@ cd ${0%/*} || exit 1 # Run from this directory
# Decompose
runApplication decomposePar -allRegions
## Can verify parallel operation of createExternalCoupledPatchGeometry
# \rm -f log.createExternalCoupledPatchGeometry
# runParallel createExternalCoupledPatchGeometry \
# -regions '(topAir heater)' coupleGroup \
# -commsDir $PWD/comms
# Run OpenFOAM