ENH: externalCoupled: changed to non-OutputFilter functionObject.

- moved control to functionObject (from bc)
- this allows multi-region support
- see heatTransfer/chtMultiRegionFoam/externalCoupledMultiRegionHeater tut
- generalisation of streamed reading/writing of specialised bcs
This commit is contained in:
mattijs
2015-11-26 13:04:06 +00:00
parent 9762ae0435
commit 29b5340b05
68 changed files with 2442 additions and 934 deletions

View File

@ -31,6 +31,7 @@ License
#include "volFields.H"
#include "globalIndex.H"
#include "fvMesh.H"
#include "DynamicField.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -65,11 +66,16 @@ Foam::fileName Foam::externalCoupledFunctionObject::baseDir() const
Foam::fileName Foam::externalCoupledFunctionObject::groupDir
(
const fileName& commsDir,
const word& regionName,
const word& regionGroupName,
const wordRe& groupName
)
{
fileName result(commsDir/regionName/string::validate<fileName>(groupName));
fileName result
(
commsDir
/regionGroupName
/string::validate<fileName>(groupName)
);
result.clean();
return result;
@ -126,11 +132,11 @@ void Foam::externalCoupledFunctionObject::removeReadFiles() const
if (log_) Info<< type() << ": removing all read files" << endl;
forAll(regionNames_, regionI)
forAll(regionGroupNames_, regionI)
{
const word& regionName = regionNames_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[regionI];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupI = groups[i];
@ -141,7 +147,7 @@ void Foam::externalCoupledFunctionObject::removeReadFiles() const
const word& fieldName = groupReadFields_[groupI][fieldI];
rm
(
groupDir(commsDir_, mesh.dbDir(), groupName)
groupDir(commsDir_, compName, groupName)
/ fieldName + ".in"
);
}
@ -159,22 +165,22 @@ void Foam::externalCoupledFunctionObject::removeWriteFiles() const
if (log_) Info<< type() << ": removing all write files" << endl;
forAll(regionNames_, regionI)
forAll(regionGroupNames_, regionI)
{
const word& regionName = regionNames_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[regionI];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupI = groups[i];
const wordRe& groupName = groupNames_[groupI];
forAll(groupWriteFields_[groupI], fieldI)
forAll(groupReadFields_[groupI], fieldI)
{
const word& fieldName = groupWriteFields_[groupI][fieldI];
const word& fieldName = groupReadFields_[groupI][fieldI];
rm
(
groupDir(commsDir_, mesh.dbDir(), groupName)
groupDir(commsDir_, compName, groupName)
/ fieldName + ".out"
);
}
@ -376,12 +382,21 @@ void Foam::externalCoupledFunctionObject::readLines
void Foam::externalCoupledFunctionObject::writeGeometry
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const fileName& commsDir,
const wordRe& groupName
)
{
fileName dir(groupDir(commsDir, mesh.dbDir(), groupName));
wordList regionNames(meshes.size());
forAll(meshes, i)
{
regionNames[i] = meshes[i].dbDir();
}
// Make sure meshes are provided in sorted order
checkOrder(regionNames);
fileName dir(groupDir(commsDir, compositeName(regionNames), groupName));
//if (log_)
{
@ -397,99 +412,210 @@ void Foam::externalCoupledFunctionObject::writeGeometry
osFacesPtr.reset(new OFstream(dir/"patchFaces"));
}
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
).sortedToc()
);
forAll(patchIDs, i)
DynamicList<face> allMeshesFaces;
DynamicField<point> allMeshesPoints;
forAll(meshes, meshI)
{
label patchI = patchIDs[i];
const fvMesh& mesh = meshes[meshI];
const polyPatch& p = mesh.boundaryMesh()[patchI];
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
).sortedToc()
);
// Count faces
label nFaces = 0;
forAll(patchIDs, i)
{
nFaces += mesh.boundaryMesh()[patchIDs[i]].size();
}
// Collect faces
DynamicList<label> allFaceIDs(nFaces);
forAll(patchIDs, i)
{
const polyPatch& p = mesh.boundaryMesh()[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
(
p.meshPoints(),
p.meshPointMap(),
allPatch.meshPoints(),
allPatch.meshPointMap(),
pointToGlobal,
uniquePointIDs
);
label procI = Pstream::myProcNo();
List<pointField> allPoints(Pstream::nProcs());
allPoints[procI] = pointField(mesh.points(), uniquePointIDs);
Pstream::gatherList(allPoints);
List<pointField> collectedPoints(Pstream::nProcs());
collectedPoints[procI] = pointField(mesh.points(), uniquePointIDs);
Pstream::gatherList(collectedPoints);
List<faceList> allFaces(Pstream::nProcs());
faceList& patchFaces = allFaces[procI];
patchFaces = p.localFaces();
List<faceList> collectedFaces(Pstream::nProcs());
faceList& patchFaces = collectedFaces[procI];
patchFaces = allPatch.localFaces();
forAll(patchFaces, faceI)
{
inplaceRenumber(pointToGlobal, patchFaces[faceI]);
}
Pstream::gatherList(allFaces);
Pstream::gatherList(collectedFaces);
if (Pstream::master())
{
pointField pts
(
ListListOps::combine<pointField>
(
allPoints,
accessOp<pointField>()
)
);
// Append and renumber
label nPoints = allMeshesPoints.size();
//if (log_)
forAll(collectedPoints, procI)
{
Info<< typeName << ": for patch " << p.name()
<< " writing " << pts.size() << " points to "
<< osPointsPtr().name() << endl;
allMeshesPoints.append(collectedPoints[procI]);
}
// Write points
osPointsPtr() << patchKey.c_str() << p.name() << pts << endl;
faceList fcs
(
ListListOps::combine<faceList>(allFaces, accessOp<faceList>())
);
//if (log_)
face newFace;
forAll(collectedFaces, procI)
{
Info<< typeName << ": for patch " << p.name()
<< " writing " << fcs.size() << " faces to "
<< osFacesPtr().name() << endl;
}
const faceList& procFaces = collectedFaces[procI];
// Write faces
osFacesPtr() << patchKey.c_str() << p.name() << fcs << endl;
forAll(procFaces, faceI)
{
const face& f = procFaces[faceI];
newFace.setSize(f.size());
forAll(f, fp)
{
newFace[fp] = f[fp]+nPoints;
}
allMeshesFaces.append(newFace);
}
nPoints += collectedPoints[procI].size();
}
}
//if (log_)
{
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;
}
}
Foam::word Foam::externalCoupledFunctionObject::compositeName
(
const wordList& regionNames
)
{
if (regionNames.size() == 0)
{
FatalErrorIn
(
"externalCoupledFunctionObject::compositeName(const wordList&)"
) << "Empty regionNames" << abort(FatalError);
return word::null;
}
else if (regionNames.size() == 1)
{
if (regionNames[0] == polyMesh::defaultRegion)
{
// For compatibility with single region cases suppress single
// region name
return word("");
}
else
{
return regionNames[0];
}
}
else
{
// Enforce lexical ordering
checkOrder(regionNames);
word composite(regionNames[0]);
for (label i = 1; i < regionNames.size(); i++)
{
composite += "_" + regionNames[i];
}
return composite;
}
}
void Foam::externalCoupledFunctionObject::checkOrder
(
const wordList& regionNames
)
{
labelList order;
sortedOrder(regionNames, order);
if (order != identity(regionNames.size()))
{
FatalErrorIn
(
"externalCoupledFunctionObject::checkOrder(const wordList&)"
) << "regionNames " << regionNames << " not in alphabetical order :"
<< order << exit(FatalError);
}
}
void Foam::externalCoupledFunctionObject::readData()
{
forAll(regionNames_, regionI)
forAll(regionGroupNames_, regionI)
{
const word& regionName = regionNames_[regionI];
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[regionI];
const wordList& regionNames = regionGroupRegions_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
// 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 labelList& patchIDs = groupPatchIDs_[groupI];
const wordList& fieldNames = groupReadFields_[groupI];
forAll(fieldNames, fieldI)
@ -498,37 +624,32 @@ void Foam::externalCoupledFunctionObject::readData()
bool ok = readData<scalar>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || readData<vector>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || readData<sphericalTensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || readData<symmTensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || readData<tensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
@ -538,7 +659,7 @@ void Foam::externalCoupledFunctionObject::readData()
(
"void Foam::externalCoupledFunctionObject::readData()"
)
<< "Field " << fieldName << " in region " << mesh.name()
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
@ -549,56 +670,59 @@ void Foam::externalCoupledFunctionObject::readData()
void Foam::externalCoupledFunctionObject::writeData() const
{
forAll(regionNames_, regionI)
forAll(regionGroupNames_, regionI)
{
const word& regionName = regionNames_[regionI];
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[regionI];
const wordList& regionNames = regionGroupRegions_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
// 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 labelList& patchIDs = groupPatchIDs_[groupI];
const wordList& fieldNames = groupWriteFields_[groupI];
forAll(fieldNames, fieldI)
{
const word& fieldName = fieldNames[fieldI];
bool ok = writeData<scalar>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || writeData<vector>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || writeData<sphericalTensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || writeData<symmTensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
ok = ok || writeData<tensor>
(
mesh,
meshes,
groupName,
patchIDs,
fieldName
);
@ -608,7 +732,7 @@ void Foam::externalCoupledFunctionObject::writeData() const
(
"void Foam::externalCoupledFunctionObject::writeData()"
)
<< "Field " << fieldName << " in region " << mesh.name()
<< "Field " << fieldName << " in regions " << compName
<< " was not found." << endl;
}
}
@ -625,12 +749,20 @@ void Foam::externalCoupledFunctionObject::initialise()
}
// Write the geometry if not already there
forAll(regionNames_, regionI)
forAll(regionGroupRegions_, i)
{
const word& regionName = regionNames_[regionI];
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[i];
const wordList& regionNames = regionGroupRegions_[i];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
// 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)
{
@ -640,14 +772,16 @@ void Foam::externalCoupledFunctionObject::initialise()
bool exists = false;
if (Pstream::master())
{
fileName dir(groupDir(commsDir_, mesh.dbDir(), groupName));
fileName dir(groupDir(commsDir_, compName, groupName));
exists = isFile(dir/"patchPoints") || isFile(dir/"patchFaces");
exists =
isFile(dir/"patchPoints")
|| isFile(dir/"patchFaces");
}
if (!returnReduce(exists, orOp<bool>()))
{
writeGeometry(mesh, commsDir_, groupName);
writeGeometry(meshes, commsDir_, groupName);
}
}
}
@ -802,6 +936,12 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
initByExternal_ = readBool(dict.lookup("initByExternal"));
log_ = dict.lookupOrDefault("log", false);
// Get names of all fvMeshes (and derived types)
wordList allRegionNames(time_.lookupClass<fvMesh>().sortedToc());
const dictionary& allRegionsDict = dict.subDict("regions");
forAllConstIter(dictionary, allRegionsDict, iter)
@ -818,9 +958,16 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
<< exit(FatalIOError);
}
const word& regionName = iter().keyword();
const wordRe regionGroupName(iter().keyword());
const dictionary& regionDict = iter().dict();
regionNames_.append(regionName);
labelList regionIDs = findStrings(regionGroupName, allRegionNames);
const wordList regionNames(allRegionNames, regionIDs);
regionGroupNames_.append(compositeName(regionNames));
regionGroupRegions_.append(regionNames);
forAllConstIter(dictionary, regionDict, regionIter)
{
@ -844,7 +991,7 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
HashTable<labelList>::iterator fnd = regionToGroups_.find
(
regionName
regionGroupNames_.last()
);
if (fnd != regionToGroups_.end())
{
@ -852,21 +999,15 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
}
else
{
regionToGroups_.insert(regionName, labelList(1, nGroups));
regionToGroups_.insert
(
regionGroupNames_.last(),
labelList(1, nGroups)
);
}
groupNames_.append(groupName);
groupReadFields_.append(readFields);
groupWriteFields_.append(writeFields);
// Pre-calculate the patchIDs
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
groupPatchIDs_.append
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
).sortedToc()
);
}
}
@ -875,25 +1016,26 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
if (log_)
{
Info<< type() << ": Communicating with regions:" << endl;
forAll(regionNames_, regionI)
forAll(regionGroupNames_, rgI)
{
const word& regionName = regionNames_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
//const wordList& regionNames = regionGroupRegions_[rgI];
const word& compName = regionGroupNames_[rgI];
Info<< "Region: " << mesh.name() << endl << incrIndent;
const labelList& groups = regionToGroups_[regionName];
Info<< "Region: " << compName << endl << incrIndent;
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupI = groups[i];
const wordRe& groupName = groupNames_[groupI];
const labelList& patchIDs = groupPatchIDs_[groupI];
Info<< indent << "Group: " << groupName << "\t"
<< " patches: " << patchIDs << endl
<< incrIndent
<< indent << "Reading fields: " << groupReadFields_[groupI]
Info<< indent << "patchGroup: " << groupName << "\t"
<< endl
<< indent << "Writing fields: " << groupWriteFields_[groupI]
<< incrIndent
<< indent << "Reading fields: "
<< groupReadFields_[groupI]
<< endl
<< indent << "Writing fields: "
<< groupWriteFields_[groupI]
<< endl
<< decrIndent;
}
@ -907,25 +1049,24 @@ bool Foam::externalCoupledFunctionObject::read(const dictionary& dict)
// should already be written - but just make sure
if (Pstream::master())
{
forAll(regionNames_, regionI)
forAll(regionGroupNames_, rgI)
{
const word& regionName = regionNames_[regionI];
const fvMesh& mesh = time_.lookupObject<fvMesh>(regionName);
const labelList& groups = regionToGroups_[regionName];
const word& compName = regionGroupNames_[rgI];
const labelList& groups = regionToGroups_[compName];
forAll(groups, i)
{
label groupI = groups[i];
const wordRe& groupName = groupNames_[groupI];
fileName dir(groupDir(commsDir_, mesh.dbDir(), groupName));
fileName dir(groupDir(commsDir_, compName, groupName));
if (!isDir(dir))
{
if (log_)
{
Info<< type() << ": creating communications directory "
<< dir << endl;
<< dir << endl;
}
mkDir(dir);
}
}

View File

@ -48,7 +48,10 @@ Description
which gets read/written on the master processor only. In the
communications directory the structure will be
<regionName>/<patchGroup>/<fieldName>.[in|out]
<regionsName>/<patchGroup>/<fieldName>.[in|out]
(where regionsName is either the name of a single region or a composite
of multiple region names)
At start-up, the boundary creates a lock file, i.e..
@ -58,13 +61,13 @@ Description
execution the boundary values are written to files (one per region,
per patch(group), per field), e.g.
<regionName>/<patchGroup>/<fieldName>.out
<regionsName>/<patchGroup>/<fieldName>.out
The lock file is then removed, instructing the external source to take
control of the program execution. When ready, the external program
should create the return values, e.g. to files
<regionName>/<patchGroup>/<fieldName>.in
<regionsName>/<patchGroup>/<fieldName>.in
... and then re-instate the lock file. The functionObject will then
read these values, apply them to the boundary conditions and pass
@ -82,7 +85,7 @@ Description
regions
{
region0
"(region1|region0)" // Name of region(s)
{
TPatchGroup // Name of patch(group)
{
@ -95,7 +98,7 @@ Description
\endverbatim
This reads/writes (on the master processor) the directory:
comms/region0/TPatchGroup/
comms/region0_region1/TPatchGroup/
with contents:
patchPoints (collected points)
patchFaces (collected faces)
@ -120,6 +123,7 @@ SourceFiles
#include "wordReList.H"
#include "scalarField.H"
#include "Switch.H"
#include "UPtrList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -167,18 +171,18 @@ class externalCoupledFunctionObject
//- Log flag
bool log_;
//- Names of regions
DynamicList<word> regionNames_;
//- Names of (composite) regions
DynamicList<word> regionGroupNames_;
// Per region the indices of the group information
// Per (composite) region the names of the regions
DynamicList<wordList> regionGroupRegions_;
// Per (composite) region the indices of the group information
HashTable<labelList> regionToGroups_;
// Per group the names of the patches/patchGroups
DynamicList<wordRe> groupNames_;
// Per group the indices of the patches
DynamicList<labelList> groupPatchIDs_;
// Per group the names of the fields to read
DynamicList<wordList> groupReadFields_;
@ -195,7 +199,7 @@ class externalCoupledFunctionObject
static fileName groupDir
(
const fileName& commsDir,
const word& regionName,
const word& regionsName,
const wordRe& groupName
);
@ -225,9 +229,8 @@ class externalCoupledFunctionObject
template<class Type>
bool readData
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const wordRe& groupName,
const labelList& patchIDs,
const word& fieldName
);
//- Read data for all regions, all fields
@ -237,9 +240,8 @@ class externalCoupledFunctionObject
template<class Type>
bool writeData
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const wordRe& groupName,
const labelList& patchIDs,
const word& fieldName
) const;
@ -275,6 +277,7 @@ class externalCoupledFunctionObject
template<class Type>
static tmp<Field<Type> > gatherAndCombine(const Field<Type>& fld);
static void checkOrder(const wordList&);
//- Disallow default bitwise copy construc
externalCoupledFunctionObject(const externalCoupledFunctionObject&);
@ -356,10 +359,14 @@ public:
// Other
//- Create single name by appending words (in sorted order),
// separated by '_'
static word compositeName(const wordList&);
//- Write geometry for the group/patch
static void writeGeometry
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const fileName& commsDir,
const wordRe& groupName
);

View File

@ -40,25 +40,20 @@ License
template<class Type>
bool Foam::externalCoupledFunctionObject::readData
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const wordRe& groupName,
const labelList& patchIDs,
const word& fieldName
)
{
typedef GeometricField<Type, fvPatchField, volMesh> volFieldType;
typedef externalCoupledMixedFvPatchField<Type> patchFieldType;
if (!mesh.foundObject<volFieldType>(fieldName))
wordList regionNames(meshes.size());
forAll(meshes, i)
{
return false;
regionNames[i] = meshes[i].dbDir();
}
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::GeometricBoundaryField& bf =
cvf.boundaryField();
// File only opened on master; contains data for all processors, for all
// patchIDs.
autoPtr<IFstream> masterFilePtr;
@ -66,7 +61,7 @@ bool Foam::externalCoupledFunctionObject::readData
{
const fileName transferFile
(
groupDir(commsDir_, mesh.dbDir(), groupName)
groupDir(commsDir_, compositeName(regionNames), groupName)
/ fieldName + ".in"
);
@ -82,181 +77,234 @@ bool Foam::externalCoupledFunctionObject::readData
(
"void externalCoupledFunctionObject::readData"
"("
"const fvMesh&, "
"const UPtrList<const fvMesh>&, "
"const wordRe&, "
"const labelList&, "
"const word&"
")",
masterFilePtr()
) << "Cannot open file for region " << mesh.name()
<< ", field " << fieldName << ", patches " << patchIDs
) << "Cannot open file for region " << compositeName(regionNames)
<< ", field " << fieldName
<< exit(FatalIOError);
}
}
// Handle column-wise reading of patch data. Supports most easy types
forAll(patchIDs, i)
label nFound = 0;
forAll(meshes, i)
{
label patchI = patchIDs[i];
const fvMesh& mesh = meshes[i];
if (isA<patchFieldType>(bf[patchI]))
if (!mesh.foundObject<volFieldType>(fieldName))
{
// Explicit handling of externalCoupledObjectMixed bcs - they have
// specialised reading routines.
patchFieldType& pf = const_cast<patchFieldType&>
(
refCast<const patchFieldType>
(
bf[patchI]
)
);
// Read from master into local stream
OStringStream os;
readLines
(
bf[patchI].size(), // number of lines to read
masterFilePtr,
os
);
// Pass responsability for all reading over to bc
pf.readData(IStringStream(os.str())());
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.patchFieldType::evaluate();
continue;
}
else if (isA<mixedFvPatchField<Type> >(bf[patchI]))
nFound++;
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::GeometricBoundaryField& bf =
cvf.boundaryField();
// Get the patches
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
List<wordRe>(1, groupName)
).sortedToc()
);
// Handle column-wise reading of patch data. Supports most easy types
forAll(patchIDs, i)
{
// Read columns from file for
// value, snGrad, refValue, refGrad, valueFraction
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
4*pTraits<Type>::nComponents+1, // nColumns: 4*Type + 1*scalar
masterFilePtr,
data
);
label patchI = patchIDs[i];
mixedFvPatchField<Type>& pf = const_cast<mixedFvPatchField<Type>&>
(
refCast<const mixedFvPatchField<Type> >
if (isA<patchFieldType>(bf[patchI]))
{
// Explicit handling of externalCoupledMixed bcs - they
// have specialised reading routines.
patchFieldType& pf = const_cast<patchFieldType&>
(
bf[patchI]
)
);
refCast<const patchFieldType>
(
bf[patchI]
)
);
// Transfer read data to bc.
// Skip value, snGrad
direction columnI = 2*pTraits<Type>::nComponents;
Field<Type>& refValue = pf.refValue();
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
{
refValue.replace(cmpt, data[columnI++]);
}
Field<Type>& refGrad = pf.refGrad();
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
{
refGrad.replace(cmpt, data[columnI++]);
}
pf.valueFraction() = data[columnI];
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.mixedFvPatchField<Type>::evaluate();
}
else if (isA<fixedGradientFvPatchField<Type> >(bf[patchI]))
{
// Read columns for value and gradient
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
2*pTraits<Type>::nComponents, // nColumns: Type
masterFilePtr,
data
);
fixedGradientFvPatchField<Type>& pf =
const_cast<fixedGradientFvPatchField<Type>&>
(
refCast<const fixedGradientFvPatchField<Type> >
// Read from master into local stream
OStringStream os;
readLines
(
bf[patchI]
)
);
bf[patchI].size(), // number of lines to read
masterFilePtr,
os
);
// Transfer gradient to bc
Field<Type>& gradient = pf.gradient();
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
// Pass responsability for all reading over to bc
pf.readData(IStringStream(os.str())());
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.patchFieldType::evaluate();
}
else if (isA<mixedFvPatchField<Type> >(bf[patchI]))
{
gradient.replace(cmpt, data[pTraits<Type>::nComponents+cmpt]);
// Read columns from file for
// value, snGrad, refValue, refGrad, valueFraction
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
4*pTraits<Type>::nComponents+1, // nColumns: 4*Type+1*scalar
masterFilePtr,
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;
Field<Type>& refValue = pf.refValue();
for
(
direction cmpt = 0;
cmpt < pTraits<Type>::nComponents;
cmpt++
)
{
refValue.replace(cmpt, data[columnI++]);
}
Field<Type>& refGrad = pf.refGrad();
for
(
direction cmpt = 0;
cmpt < pTraits<Type>::nComponents;
cmpt++
)
{
refGrad.replace(cmpt, data[columnI++]);
}
pf.valueFraction() = data[columnI];
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.mixedFvPatchField<Type>::evaluate();
}
else if (isA<fixedGradientFvPatchField<Type> >(bf[patchI]))
{
// Read columns for value and gradient
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
2*pTraits<Type>::nComponents, // nColumns: Type
masterFilePtr,
data
);
fixedGradientFvPatchField<Type>& pf =
const_cast<fixedGradientFvPatchField<Type>&>
(
refCast<const fixedGradientFvPatchField<Type> >
(
bf[patchI]
)
);
// Transfer gradient to bc
Field<Type>& gradient = pf.gradient();
for
(
direction cmpt = 0;
cmpt < pTraits<Type>::nComponents;
cmpt++
)
{
gradient.replace
(
cmpt,
data[pTraits<Type>::nComponents+cmpt]
);
}
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.fixedGradientFvPatchField<Type>::evaluate();
}
else if (isA<fixedValueFvPatchField<Type> >(bf[patchI]))
{
// Read columns for value only
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
pTraits<Type>::nComponents, // number of columns to read
masterFilePtr,
data
);
// Transfer read value to bc
Field<Type> value(bf[patchI].size());
for
(
direction cmpt = 0;
cmpt < pTraits<Type>::nComponents;
cmpt++
)
{
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
// additional processing by derived type.
pf.fixedValueFvPatchField<Type>::evaluate();
}
else
{
FatalErrorIn
(
"void externalCoupledFunctionObject::readData"
"("
"const UPtrList<const fvMesh>&, "
"const wordRe&, "
"const word&"
")"
)
<< "Unsupported boundary condition " << bf[patchI].type()
<< " for patch " << bf[patchI].patch().name()
<< " in region " << mesh.name()
<< exit(FatalError);
}
// Update the value from the read coefficicient. Bypass any
// additional processing by derived type.
pf.fixedGradientFvPatchField<Type>::evaluate();
initialised_ = true;
}
else if (isA<fixedValueFvPatchField<Type> >(bf[patchI]))
{
// Read columns for value only
List<scalarField> data;
readColumns
(
bf[patchI].size(), // number of lines to read
pTraits<Type>::nComponents, // number of columns to read
masterFilePtr,
data
);
// Transfer read value to bc
Field<Type> value(bf[patchI].size());
for (direction cmpt = 0; cmpt < pTraits<Type>::nComponents; cmpt++)
{
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
// additional processing by derived type.
pf.fixedValueFvPatchField<Type>::evaluate();
}
else
{
FatalErrorIn
(
"void externalCoupledFunctionObject::readData"
"("
"const fvMesh&, "
"const wordRe&, "
"const labelList&, "
"const word&"
")"
)
<< "Unsupported boundary condition " << bf[patchI].type()
<< " for patch " << bf[patchI].patch().name()
<< " in region " << mesh.name()
<< exit(FatalError);
}
initialised_ = true;
}
return true;
return nFound > 0;
}
@ -308,25 +356,20 @@ Foam::externalCoupledFunctionObject::gatherAndCombine
template<class Type>
bool Foam::externalCoupledFunctionObject::writeData
(
const fvMesh& mesh,
const UPtrList<const fvMesh>& meshes,
const wordRe& groupName,
const labelList& patchIDs,
const word& fieldName
) const
{
typedef GeometricField<Type, fvPatchField, volMesh> volFieldType;
typedef externalCoupledMixedFvPatchField<Type> patchFieldType;
if (!mesh.foundObject<volFieldType>(fieldName))
wordList regionNames(meshes.size());
forAll(meshes, i)
{
return false;
regionNames[i] = meshes[i].dbDir();
}
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::GeometricBoundaryField& bf =
cvf.boundaryField();
// File only opened on master; contains data for all processors, for all
// patchIDs
autoPtr<OFstream> masterFilePtr;
@ -334,7 +377,7 @@ bool Foam::externalCoupledFunctionObject::writeData
{
const fileName transferFile
(
groupDir(commsDir_, mesh.dbDir(), groupName)
groupDir(commsDir_, compositeName(regionNames), groupName)
/ fieldName + ".out"
);
@ -350,14 +393,13 @@ bool Foam::externalCoupledFunctionObject::writeData
(
"externalCoupledFunctionObject::writeData"
"("
"const fvMesh&, "
"const UPtrList<const fvMesh>&, "
"const wordRe&, "
"const labelList&, "
"const word&"
") const",
masterFilePtr()
) << "Cannot open file for region " << mesh.name()
<< ", field " << fieldName << ", patches " << patchIDs
) << "Cannot open file for region " << compositeName(regionNames)
<< ", field " << fieldName
<< exit(FatalIOError);
}
}
@ -365,94 +407,122 @@ bool Foam::externalCoupledFunctionObject::writeData
bool headerDone = false;
// Handle column-wise writing of patch data. Supports most easy types
forAll(patchIDs, i)
label nFound = 0;
forAll(meshes, i)
{
label patchI = patchIDs[i];
const fvMesh& mesh = meshes[i];
const globalIndex globalFaces(bf[patchI].size());
if (isA<patchFieldType>(bf[patchI]))
if (!mesh.foundObject<volFieldType>(fieldName))
{
// Explicit handling of externalCoupledObjectMixed bcs - they have
// specialised writing routines
continue;
}
const patchFieldType& pf = refCast<const patchFieldType>
nFound++;
const volFieldType& cvf = mesh.lookupObject<volFieldType>(fieldName);
const typename volFieldType::GeometricBoundaryField& bf =
cvf.boundaryField();
// Get the patches
const labelList patchIDs
(
mesh.boundaryMesh().patchSet
(
bf[patchI]
);
OStringStream os;
List<wordRe>(1, groupName)
).sortedToc()
);
// Pass responsibility for all writing over to bc
pf.writeData(os);
// Handle column-wise writing of patch data. Supports most easy types
forAll(patchIDs, i)
{
label patchI = patchIDs[i];
// Collect contributions from all processors and output them on
// master
if (Pstream::master())
const globalIndex globalFaces(bf[patchI].size());
if (isA<patchFieldType>(bf[patchI]))
{
// Output master data first
if (!headerDone)
{
pf.writeHeader(masterFilePtr());
headerDone = true;
}
masterFilePtr() << os.str().c_str();
// Explicit handling of externalCoupledMixed bcs - they
// have specialised writing routines
for (label procI = 1; procI < Pstream::nProcs(); procI++)
const patchFieldType& pf = refCast<const patchFieldType>
(
bf[patchI]
);
OStringStream os;
// Pass responsibility for all writing over to bc
pf.writeData(os);
// Collect contributions from all processors and output them on
// master
if (Pstream::master())
{
IPstream fromSlave(Pstream::scheduled, procI);
string str(fromSlave);
masterFilePtr() << str.c_str();
// Output master data first
if (!headerDone)
{
pf.writeHeader(masterFilePtr());
headerDone = true;
}
masterFilePtr() << os.str().c_str();
for (label procI = 1; procI < Pstream::nProcs(); procI++)
{
IPstream fromSlave(Pstream::scheduled, procI);
string str(fromSlave);
masterFilePtr() << str.c_str();
}
}
else
{
OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
toMaster << os.str();
}
}
else if (isA<mixedFvPatchField<Type> >(bf[patchI]))
{
const mixedFvPatchField<Type>& pf =
refCast<const mixedFvPatchField<Type> >(bf[patchI]);
Field<Type> value(gatherAndCombine(pf));
Field<Type> snGrad(gatherAndCombine(pf.snGrad()()));
Field<Type> refValue(gatherAndCombine(pf.refValue()));
Field<Type> refGrad(gatherAndCombine(pf.refGrad()));
scalarField valueFraction(gatherAndCombine(pf.valueFraction()));
if (Pstream::master())
{
forAll(refValue, faceI)
{
masterFilePtr()
<< value[faceI] << token::SPACE
<< snGrad[faceI] << token::SPACE
<< refValue[faceI] << token::SPACE
<< refGrad[faceI] << token::SPACE
<< valueFraction[faceI] << nl;
}
}
}
else
{
OPstream toMaster(Pstream::scheduled, Pstream::masterNo());
toMaster << os.str();
}
}
else if (isA<mixedFvPatchField<Type> >(bf[patchI]))
{
const mixedFvPatchField<Type>& pf =
refCast<const mixedFvPatchField<Type> >(bf[patchI]);
Field<Type> value(gatherAndCombine(pf));
Field<Type> snGrad(gatherAndCombine(pf.snGrad()()));
Field<Type> refValue(gatherAndCombine(pf.refValue()));
Field<Type> refGrad(gatherAndCombine(pf.refGrad()));
scalarField valueFraction(gatherAndCombine(pf.valueFraction()));
if (Pstream::master())
{
forAll(refValue, faceI)
// Output the value and snGrad
Field<Type> value(gatherAndCombine(bf[patchI]));
Field<Type> snGrad(gatherAndCombine(bf[patchI].snGrad()()));
if (Pstream::master())
{
masterFilePtr()
<< value[faceI] << token::SPACE
<< snGrad[faceI] << token::SPACE
<< refValue[faceI] << token::SPACE
<< refGrad[faceI] << token::SPACE
<< valueFraction[faceI] << nl;
}
}
}
else
{
// Output the value and snGrad
Field<Type> value(gatherAndCombine(bf[patchI]));
Field<Type> snGrad(gatherAndCombine(bf[patchI].snGrad()()));
if (Pstream::master())
{
forAll(value, faceI)
{
masterFilePtr()
<< value[faceI] << token::SPACE
<< snGrad[faceI] << nl;
forAll(value, faceI)
{
masterFilePtr()
<< value[faceI] << token::SPACE
<< snGrad[faceI] << nl;
}
}
}
}
}
return true;
return nFound > 0;
}