mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
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:
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user