ENH: initial revamp of faMesh to improve modularity (#2084)

- improved separation of patch creation that is also parallel-aware,
  which now allows creation in parallel

- memory-safe use of PtrList for adding patches, with a more generalized
  faPatchData helper

- use uindirectPrimitivePatch instead of indirectPrimitivePatch
  for internal patch handling.

- align boundary methods with polyMesh equivalents

- system/faMeshDefinition instead of constant/faMesh/faMeshDefinition
  as per blockMesh convention. Easier to manage definitions, easier
  for cleanup.

- drop inheritence from GeoMesh.
This commit is contained in:
Mark Olesen
2021-05-11 07:30:00 +02:00
parent 0a5a0c29d7
commit 0cf4aede6e
28 changed files with 1757 additions and 1349 deletions

View File

@ -1,8 +1,12 @@
EXE_INC = \
-I$(LIB_SRC)/finiteArea/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/cfdTools/general/lnInclude
EXE_LIBS = \
-lfiniteArea \
-lfiniteVolume
-lfiniteVolume \
-lfileFormats \
-lmeshTools

View File

@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Description
placeholder for decomposing fields
\*---------------------------------------------------------------------------*/
if (Pstream::parRun())
{
}
// ************************************************************************* //

View File

@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
Description
Search for the appropriate faMeshDefinition dictionary....
\*---------------------------------------------------------------------------*/
const word dictName("faMeshDefinition");
autoPtr<IOdictionary> meshDictPtr;
{
fileName dictPath;
const word& regionDir =
(regionName == polyMesh::defaultRegion ? word::null : regionName);
if (args.readIfPresent("dict", dictPath))
{
// Dictionary specified on the command-line ...
if (isDir(dictPath))
{
dictPath /= dictName;
}
}
else if
(
// Check global location
exists
(
runTime.path()/runTime.caseConstant()
/regionDir/faMesh::meshSubDir/dictName
)
)
{
// Dictionary present in constant faMesh directory (old-style)
dictPath =
runTime.constant()
/regionDir/faMesh::meshSubDir/dictName;
// Warn that constant/faMesh/faMeshDefinition was used
// instead of system/faMeshDefinition
#if 0
WarningIn(args.executable())
<< "Using the old faMeshDefinition location: "
<< dictPath << nl
<< " instead of default location: "
<< runTime.system()/regionDir/dictName << nl
<< endl;
#endif
}
else
{
// Assume dictionary is in the system directory
dictPath = runTime.system()/regionDir/dictName;
}
IOobject meshDictIO
(
dictPath,
runTime,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false, // no registerObject
true // is globalObject
);
if (!meshDictIO.typeHeaderOk<IOdictionary>(true))
{
FatalErrorInFunction
<< meshDictIO.objectPath() << nl
<< exit(FatalError);
}
Info<< "Creating faMesh from definition: "
<< runTime.relativePath(meshDictIO.objectPath()) << endl;
meshDictPtr = autoPtr<IOdictionary>::New(meshDictIO);
}
IOdictionary& meshDefDict = *meshDictPtr;
// ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -41,30 +42,12 @@ Author
#include "OSspecific.H"
#include "faMesh.H"
#include "fvMesh.H"
#include "IOdictionary.H"
#include "globalIndex.H"
#include "globalMeshData.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
class faPatchData
{
public:
word name_;
word type_;
dictionary dict_;
label ownPolyPatchID_;
label ngbPolyPatchID_;
labelList edgeLabels_;
faPatchData()
:
name_(word::null),
type_(word::null),
ownPolyPatchID_(-1),
ngbPolyPatchID_(-1)
{}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
@ -73,286 +56,40 @@ int main(int argc, char *argv[])
(
"A mesh generator for finiteArea mesh"
);
argList::addOption
(
"empty-patch",
"name",
"Specify name for a default empty patch",
false // An advanced option, but not enough to worry about that
);
argList::addOption("dict", "file", "Alternative faMeshDefinition");
#include "addRegionOption.H"
argList::noParallel();
#include "setRootCase.H"
#include "createTime.H"
#include "createNamedMesh.H"
// Reading faMeshDefinition dictionary
IOdictionary faMeshDefinition
(
IOobject
(
"faMeshDefinition",
runTime.constant(),
"faMesh",
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE
)
);
#include "findMeshDefinitionDict.H"
wordList polyMeshPatches
(
faMeshDefinition.get<wordList>("polyMeshPatches")
);
const dictionary& bndDict = faMeshDefinition.subDict("boundary");
const wordList faPatchNames(bndDict.toc());
List<faPatchData> faPatches(faPatchNames.size()+1);
forAll(faPatchNames, patchI)
// Inject/overwrite name for optional 'empty' patch
word patchName;
if (args.readIfPresent("empty-patch", patchName))
{
const dictionary& curPatchDict = bndDict.subDict(faPatchNames[patchI]);
faPatches[patchI].name_ = faPatchNames[patchI];
faPatches[patchI].type_ = curPatchDict.get<word>("type");
const word ownName(curPatchDict.get<word>("ownerPolyPatch"));
faPatches[patchI].ownPolyPatchID_ =
mesh.boundaryMesh().findPatchID(ownName);
if (faPatches[patchI].ownPolyPatchID_ < 0)
{
FatalErrorIn("makeFaMesh:")
<< "neighbourPolyPatch " << ownName << " does not exist"
<< exit(FatalError);
}
const word neiName(curPatchDict.get<word>("neighbourPolyPatch"));
faPatches[patchI].ngbPolyPatchID_ =
mesh.boundaryMesh().findPatchID(neiName);
if (faPatches[patchI].ngbPolyPatchID_ < 0)
{
FatalErrorIn("makeFaMesh:")
<< "neighbourPolyPatch " << neiName << " does not exist"
<< exit(FatalError);
}
meshDefDict.add("emptyPatch", patchName, true);
}
// Setting faceLabels list size
label size = 0;
labelList patchIDs(polyMeshPatches.size(), -1);
forAll(polyMeshPatches, patchI)
{
patchIDs[patchI] =
mesh.boundaryMesh().findPatchID(polyMeshPatches[patchI]);
if (patchIDs[patchI] < 0)
{
FatalErrorIn("makeFaMesh:")
<< "Patch " << polyMeshPatches[patchI] << " does not exist"
<< exit(FatalError);
}
size += mesh.boundaryMesh()[patchIDs[patchI]].size();
}
labelList faceLabels(size, -1);
sort(patchIDs);
// Filling of faceLabels list
label faceI = -1;
forAll(polyMeshPatches, patchI)
{
label start = mesh.boundaryMesh()[patchIDs[patchI]].start();
label size = mesh.boundaryMesh()[patchIDs[patchI]].size();
for (label i = 0; i < size; ++i)
{
faceLabels[++faceI] = start + i;
}
}
// Creating faMesh
Info << "Create faMesh ... ";
faMesh areaMesh
(
mesh,
faceLabels
);
Info << "Done" << endl;
// Determination of faPatch ID for each boundary edge.
// Result is in the bndEdgeFaPatchIDs list
const indirectPrimitivePatch& patch = areaMesh.patch();
labelList faceCells(faceLabels.size(), -1);
forAll(faceCells, faceI)
{
label faceID = faceLabels[faceI];
faceCells[faceI] = mesh.faceOwner()[faceID];
}
labelList meshEdges =
patch.meshEdges
(
mesh.edges(),
mesh.cellEdges(),
faceCells
);
const labelListList& edgeFaces = mesh.edgeFaces();
const label nTotalEdges = patch.nEdges();
const label nInternalEdges = patch.nInternalEdges();
labelList bndEdgeFaPatchIDs(nTotalEdges - nInternalEdges, -1);
for (label edgeI = nInternalEdges; edgeI < nTotalEdges; ++edgeI)
{
label curMeshEdge = meshEdges[edgeI];
labelList curEdgePatchIDs(2, label(-1));
label patchI = -1;
forAll(edgeFaces[curMeshEdge], faceI)
{
label curFace = edgeFaces[curMeshEdge][faceI];
label curPatchID = mesh.boundaryMesh().whichPatch(curFace);
if (curPatchID != -1)
{
curEdgePatchIDs[++patchI] = curPatchID;
}
}
for (label pI = 0; pI < faPatches.size() - 1; ++pI)
{
if
(
(
curEdgePatchIDs[0] == faPatches[pI].ownPolyPatchID_
&& curEdgePatchIDs[1] == faPatches[pI].ngbPolyPatchID_
)
||
(
curEdgePatchIDs[1] == faPatches[pI].ownPolyPatchID_
&& curEdgePatchIDs[0] == faPatches[pI].ngbPolyPatchID_
)
)
{
bndEdgeFaPatchIDs[edgeI - nInternalEdges] = pI;
break;
}
}
}
// Set edgeLabels for each faPatch
for (label pI=0; pI<(faPatches.size()-1); ++pI)
{
SLList<label> tmpList;
forAll(bndEdgeFaPatchIDs, eI)
{
if (bndEdgeFaPatchIDs[eI] == pI)
{
tmpList.append(nInternalEdges + eI);
}
}
faPatches[pI].edgeLabels_ = tmpList;
}
// Check for undefined edges
SLList<label> tmpList;
forAll(bndEdgeFaPatchIDs, eI)
{
if (bndEdgeFaPatchIDs[eI] == -1)
{
tmpList.append(nInternalEdges + eI);
}
}
if (tmpList.size() > 0)
{
label pI = faPatches.size()-1;
faPatches[pI].name_ = "undefined";
faPatches[pI].type_ = "patch";
faPatches[pI].edgeLabels_ = tmpList;
}
// Add good patches to faMesh
SLList<faPatch*> faPatchLst;
for (label pI = 0; pI < faPatches.size(); ++pI)
{
faPatches[pI].dict_.add("type", faPatches[pI].type_);
faPatches[pI].dict_.add("edgeLabels", faPatches[pI].edgeLabels_);
faPatches[pI].dict_.add
(
"ngbPolyPatchIndex",
faPatches[pI].ngbPolyPatchID_
);
if(faPatches[pI].edgeLabels_.size() > 0)
{
faPatchLst.append
(
faPatch::New
(
faPatches[pI].name_,
faPatches[pI].dict_,
pI,
areaMesh.boundary()
).ptr()
);
}
}
word emptyPatchName;
if (args.readIfPresent("addEmptyPatch", emptyPatchName))
{
dictionary emptyPatchDict;
emptyPatchDict.add("type", "empty");
emptyPatchDict.add("edgeLabels", labelList());
emptyPatchDict.add("ngbPolyPatchIndex", -1);
faPatchLst.append
(
faPatch::New
(
emptyPatchName,
emptyPatchDict,
faPatchLst.size(),
areaMesh.boundary()
).ptr()
);
}
Info << "Add faPatches ... ";
areaMesh.addFaPatches(List<faPatch*>(faPatchLst));
Info << "Done" << endl;
// Creation
faMesh areaMesh(mesh, meshDefDict);
// Writing faMesh
Info << "Write finite area mesh ... ";
areaMesh.write();
Info << "\nEnd" << endl;
#include "decomposeFaFields.H"
Info << "\nEnd\n" << endl;
return 0;
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2018-2019 OpenCFD Ltd.
Copyright (C) 2018-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -41,6 +41,8 @@ License
void Foam::faMeshDecomposition::distributeFaces()
{
const word& polyMeshRegionName = mesh().name();
Info<< "\nCalculating distribution of faces" << endl;
cpuTime decompositionTime;
@ -58,7 +60,7 @@ void Foam::faMeshDecomposition::distributeFaces()
(
IOobject
(
GeoMesh<polyMesh>::mesh_.name(),
polyMeshRegionName,
processorDb.timeName(),
processorDb
)
@ -214,6 +216,8 @@ void Foam::faMeshDecomposition::decomposeMesh()
// Decide which cell goes to which processor
distributeFaces();
const word& polyMeshRegionName = mesh().name();
Info<< "\nDistributing faces to processors" << endl;
// Memory management
@ -224,9 +228,9 @@ void Foam::faMeshDecomposition::decomposeMesh()
{
if (faceToProc_[faceI] >= nProcs())
{
FatalErrorIn("Finite area mesh decomposition")
FatalErrorInFunction
<< "Impossible processor label " << faceToProc_[faceI]
<< "for face " << faceI
<< "for face " << faceI << nl
<< abort(FatalError);
}
else
@ -258,7 +262,7 @@ void Foam::faMeshDecomposition::decomposeMesh()
(
IOobject
(
GeoMesh<polyMesh>::mesh_.name(),
polyMeshRegionName,
processorDb.timeName(),
processorDb
)
@ -314,7 +318,7 @@ void Foam::faMeshDecomposition::decomposeMesh()
fvFaceProcAddressingHash.find
(
faceLabels()[curProcFaceAddressing[faceI]] + 1
)();
).val();
}
// create processor finite area mesh
@ -324,38 +328,35 @@ void Foam::faMeshDecomposition::decomposeMesh()
procFaceLabels_[procI]
);
const indirectPrimitivePatch& patch = this->patch();
const uindirectPrimitivePatch& patch = this->patch();
const Map<label>& map = patch.meshPointMap();
EdgeMap<label> edgesHash;
label edgeI = -1;
const label nIntEdges = patch.nInternalEdges();
for (label curEdge = 0; curEdge < nIntEdges; curEdge++)
for (label edgei = 0; edgei < nIntEdges; ++edgei)
{
edgesHash.insert(patch.edges()[curEdge], ++edgeI);
edgesHash.insert(patch.edges()[edgei], edgesHash.size());
}
forAll(boundary(), patchI)
forAll(boundary(), patchi)
{
// Include emptyFaPatch
const label size = boundary()[patchi].labelList::size();
const label size = boundary()[patchI].labelList::size();
for(int eI=0; eI<size; eI++)
for (label edgei=0; edgei < size; ++edgei)
{
edgesHash.insert
(
patch.edges()[boundary()[patchI][eI]],
++edgeI
patch.edges()[boundary()[patchi][edgei]],
edgesHash.size()
);
}
}
const indirectPrimitivePatch& procPatch = procMesh.patch();
const uindirectPrimitivePatch& procPatch = procMesh.patch();
const vectorField& procPoints = procPatch.localPoints();
const labelList& procMeshPoints = procPatch.meshPoints();
const edgeList& procEdges = procPatch.edges();
@ -370,21 +371,18 @@ void Foam::faMeshDecomposition::decomposeMesh()
}
labelList& curPatchEdgeAddressing = procPatchEdgeAddressing_[procI];
curPatchEdgeAddressing.setSize(procEdges.size(), -1);
curPatchEdgeAddressing.resize(procEdges.size(), -1);
Map<label>& curMap = procMeshEdgesMap_[procI];
curMap.clear();
curMap.resize(2*procEdges.size());
forAll(procEdges, edgeI)
{
edge curGlobalEdge = procEdges[edgeI];
curGlobalEdge[0] = curPatchPointAddressing[curGlobalEdge[0]];
curGlobalEdge[1] = curPatchPointAddressing[curGlobalEdge[1]];
curPatchEdgeAddressing[edgeI] = edgesHash.find(curGlobalEdge)();
edge curGlobalEdge(curPatchPointAddressing, procEdges[edgeI]);
curPatchEdgeAddressing[edgeI] = edgesHash.find(curGlobalEdge).val();
}
Map<label>& curMap = procMeshEdgesMap_[procI];
curMap = Map<label>(2*procEdges.size());
forAll(curPatchEdgeAddressing, edgeI)
{
curMap.insert(curPatchEdgeAddressing[edgeI], edgeI);
@ -1057,7 +1055,7 @@ void Foam::faMeshDecomposition::decomposeMesh()
(
IOobject
(
GeoMesh<polyMesh>::mesh_.name(),
polyMeshRegionName,
processorDb.timeName(),
processorDb
)
@ -1137,8 +1135,9 @@ void Foam::faMeshDecomposition::decomposeMesh()
bool Foam::faMeshDecomposition::writeDecomposition()
{
Info<< "\nConstructing processor FA meshes" << endl;
const word& polyMeshRegionName = mesh().name();
Info<< "\nConstructing processor FA meshes" << endl;
// Make a lookup map for globally shared points
Map<label> sharedPointLookup(2*globallySharedPoints_.size());
@ -1175,7 +1174,7 @@ bool Foam::faMeshDecomposition::writeDecomposition()
(
IOobject
(
GeoMesh<polyMesh>::mesh_.name(),
polyMeshRegionName,
processorDb.timeName(),
processorDb
)
@ -1195,7 +1194,7 @@ bool Foam::faMeshDecomposition::writeDecomposition()
);
// create finite area mesh
// Create finite area mesh
faMesh procMesh
(
procFvMesh,
@ -1219,11 +1218,9 @@ bool Foam::faMeshDecomposition::writeDecomposition()
const faPatchList& meshPatches = boundary();
List<faPatch*> procPatches
PtrList<faPatch> procPatches
(
curPatchSizes.size()
+ curProcessorPatchSizes.size(),
reinterpret_cast<faPatch*>(NULL)
curPatchSizes.size() + curProcessorPatchSizes.size()
);
label nPatches = 0;
@ -1232,44 +1229,51 @@ bool Foam::faMeshDecomposition::writeDecomposition()
{
const labelList& curEdgeLabels = curPatchEdgeLabels[nPatches];
const label ngbPolyPatchIndex =
const label neiPolyPatchId =
fvBoundaryProcAddressing.find
(
meshPatches[curBoundaryAddressing[patchi]]
.ngbPolyPatchIndex()
);
procPatches[nPatches] =
procPatches.set
(
nPatches,
meshPatches[curBoundaryAddressing[patchi]].clone
(
procMesh.boundary(),
curEdgeLabels,
nPatches,
ngbPolyPatchIndex
).ptr();
nPatches++;
neiPolyPatchId
)
);
++nPatches;
}
forAll(curProcessorPatchSizes, procPatchI)
{
const labelList& curEdgeLabels = curPatchEdgeLabels[nPatches];
procPatches[nPatches] =
procPatches.set
(
nPatches,
new processorFaPatch
(
word("procBoundary") + Foam::name(procI)
+ word("to")
+ Foam::name(curNeighbourProcessors[procPatchI]),
processorPolyPatch::newName
(
procI,
curNeighbourProcessors[procPatchI]
),
curEdgeLabels,
nPatches,
procMesh.boundary(),
-1,
procI,
curNeighbourProcessors[procPatchI]
);
)
);
nPatches++;
++nPatches;
}
// Add boundary patches
@ -1291,23 +1295,19 @@ bool Foam::faMeshDecomposition::writeDecomposition()
forAll(procMesh.boundary(), patchi)
{
if
(
procMesh.boundary()[patchi].type()
== processorFaPatch::typeName
)
const auto* ppp =
isA<processorFaPatch>(procMesh.boundary()[patchi]);
if (ppp)
{
const processorFaPatch& ppp =
refCast<const processorFaPatch>
(
procMesh.boundary()[patchi]
);
const auto& procPatch = *ppp;
Info<< " Number of edges shared with processor "
<< ppp.neighbProcNo() << " = " << ppp.size() << endl;
<< procPatch.neighbProcNo() << " = "
<< procPatch.size() << endl;
nProcPatches++;
nProcEdges += ppp.size();
nProcEdges += procPatch.size();
++nProcPatches;
}
else
{

View File

@ -39,7 +39,7 @@ SourceFiles
#define writeAreaFields_H
#include "readFields.H"
#include "foamVtkIndPatchGeoFieldsWriter.H"
#include "foamVtkUIndPatchGeoFieldsWriter.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -47,7 +47,7 @@ namespace Foam
{
// Writer type for finite-area mesh + fields
typedef vtk::indirectPatchGeoFieldsWriter vtkWriterType_areaMesh;
typedef vtk::uindirectPatchGeoFieldsWriter vtkWriterType_areaMesh;
template<class GeoField>
bool writeAreaField