mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add global topology check in checkMesh and makeFaMesh (#2771)
- detect when boundary patches are multiply connected across edges STYLE: initialize some faMesh values
This commit is contained in:
@ -0,0 +1,164 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
|
||||
|
||||
Description
|
||||
Check topology of poly patches used for finite-area.
|
||||
|
||||
Input
|
||||
mesh (polyMesh)
|
||||
meshDefDict (system/faMeshDefintion)
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// Preliminary checks
|
||||
{
|
||||
typedef typename uindirectPrimitivePatch::surfaceTopo TopoType;
|
||||
|
||||
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
|
||||
|
||||
wordRes polyPatchNames;
|
||||
meshDefDict.readIfPresent("polyMeshPatches", polyPatchNames);
|
||||
|
||||
const labelList patchIDs
|
||||
(
|
||||
pbm.patchSet
|
||||
(
|
||||
polyPatchNames,
|
||||
false, // warnNotFound
|
||||
true // useGroups
|
||||
).sortedToc()
|
||||
);
|
||||
|
||||
label nFaceLabels = 0;
|
||||
for (const label patchi : patchIDs)
|
||||
{
|
||||
nFaceLabels += pbm[patchi].size();
|
||||
}
|
||||
|
||||
labelList faceLabels(nFaceLabels);
|
||||
|
||||
nFaceLabels = 0;
|
||||
for (const label patchi : patchIDs)
|
||||
{
|
||||
for (const label facei : pbm[patchi].range())
|
||||
{
|
||||
faceLabels[nFaceLabels] = facei;
|
||||
++nFaceLabels;
|
||||
}
|
||||
}
|
||||
|
||||
uindirectPrimitivePatch pp
|
||||
(
|
||||
UIndirectList<face>(mesh.faces(), faceLabels),
|
||||
mesh.points()
|
||||
);
|
||||
|
||||
// Non-manifold
|
||||
labelHashSet badEdges(pp.nEdges()/20);
|
||||
|
||||
labelHashSet* pointSetPtr = nullptr;
|
||||
labelHashSet* badEdgesPtr = &badEdges;
|
||||
|
||||
bool foundError = false;
|
||||
|
||||
if (returnReduceAnd(pp.empty()))
|
||||
{
|
||||
// Empty
|
||||
}
|
||||
else if (UPstream::parRun())
|
||||
{
|
||||
const labelList meshEdges
|
||||
(
|
||||
pp.meshEdges(mesh.edges(), mesh.pointEdges())
|
||||
);
|
||||
|
||||
// Parallel - use mesh edges
|
||||
// - no check for point-pinch
|
||||
// - no check for consistent orientation (if that is posible to
|
||||
// check?)
|
||||
|
||||
// Count number of edge/face connections (globally)
|
||||
labelList nEdgeConnections(mesh.nEdges(), Zero);
|
||||
|
||||
const labelListList& edgeFaces = pp.edgeFaces();
|
||||
|
||||
forAll(edgeFaces, edgei)
|
||||
{
|
||||
nEdgeConnections[meshEdges[edgei]] = edgeFaces[edgei].size();
|
||||
}
|
||||
|
||||
// Synchronise across coupled edges
|
||||
syncTools::syncEdgeList
|
||||
(
|
||||
mesh,
|
||||
nEdgeConnections,
|
||||
plusEqOp<label>(),
|
||||
label(0) // null value
|
||||
);
|
||||
|
||||
label labelTyp = TopoType::MANIFOLD;
|
||||
forAll(meshEdges, edgei)
|
||||
{
|
||||
const label meshEdgei = meshEdges[edgei];
|
||||
const label numNbrs = nEdgeConnections[meshEdgei];
|
||||
if (numNbrs == 1)
|
||||
{
|
||||
//if (pointSetPtr) pointSetPtr->insert(mesh.edges()[meshEdgei]);
|
||||
labelTyp = max(labelTyp, TopoType::OPEN);
|
||||
}
|
||||
else if (numNbrs == 0 || numNbrs > 2)
|
||||
{
|
||||
if (pointSetPtr) pointSetPtr->insert(mesh.edges()[meshEdgei]);
|
||||
if (badEdgesPtr) badEdgesPtr->insert(edgei);
|
||||
labelTyp = max(labelTyp, TopoType::ILLEGAL);
|
||||
}
|
||||
}
|
||||
reduce(labelTyp, maxOp<label>());
|
||||
|
||||
foundError = (labelTyp == TopoType::ILLEGAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
const TopoType pTyp = pp.surfaceType(badEdgesPtr);
|
||||
|
||||
foundError = (pTyp == TopoType::ILLEGAL);
|
||||
}
|
||||
|
||||
if (foundError)
|
||||
{
|
||||
edgeList dumpEdges(pp.edges(), badEdges.sortedToc());
|
||||
|
||||
vtk::lineWriter writer
|
||||
(
|
||||
pp.localPoints(),
|
||||
dumpEdges,
|
||||
fileName
|
||||
(
|
||||
mesh.time().globalPath()
|
||||
/ ("faMesh-construct.illegalEdges")
|
||||
)
|
||||
);
|
||||
|
||||
writer.writeGeometry();
|
||||
|
||||
// CellData
|
||||
writer.beginCellData();
|
||||
writer.writeProcIDs();
|
||||
|
||||
Info<< "Wrote "
|
||||
<< returnReduce(dumpEdges.size(), sumOp<label>())
|
||||
<< " bad edges: " << writer.output().name() << nl;
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -16,10 +16,10 @@ Description
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
// Embed do-while to support early termination
|
||||
if (doDecompose && Pstream::parRun())
|
||||
if (doDecompose && UPstream::parRun())
|
||||
do
|
||||
{
|
||||
faMeshReconstructor reconstructor(aMesh, IOobjectOption::READ_IF_PRESENT);
|
||||
faMeshReconstructor reconstructor(aMesh, IOobjectOption::LAZY_READ);
|
||||
|
||||
if (!reconstructor.good())
|
||||
{
|
||||
@ -61,16 +61,16 @@ do
|
||||
auto oldHandler = fileHandler(fileOperation::NewUncollated());
|
||||
fileHandler().distributed(true);
|
||||
|
||||
if (Pstream::master())
|
||||
if (UPstream::master())
|
||||
{
|
||||
haveMeshOnProc.set(Pstream::myProcNo());
|
||||
haveMeshOnProc.set(UPstream::myProcNo());
|
||||
subsetter.reset(new faMeshSubset(serialMesh));
|
||||
|
||||
const bool oldParRun = Pstream::parRun(false);
|
||||
const bool oldParRun = UPstream::parRun(false);
|
||||
|
||||
objects = IOobjectList(serialMesh.time(), runTime.timeName());
|
||||
|
||||
Pstream::parRun(oldParRun);
|
||||
UPstream::parRun(oldParRun);
|
||||
}
|
||||
|
||||
// Restore old settings
|
||||
|
||||
@ -21,12 +21,12 @@ Description
|
||||
|
||||
word outputName("finiteArea-edges.obj");
|
||||
|
||||
if (Pstream::parRun())
|
||||
if (UPstream::parRun())
|
||||
{
|
||||
outputName = word
|
||||
(
|
||||
"finiteArea-edges-proc"
|
||||
+ Foam::name(Pstream::myProcNo())
|
||||
+ Foam::name(UPstream::myProcNo())
|
||||
+ ".obj"
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2016-2017 Wikki Ltd
|
||||
Copyright (C) 2021-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2021-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -51,7 +51,9 @@ Original Authors
|
||||
#include "faMeshReconstructor.H"
|
||||
#include "faMeshSubset.H"
|
||||
#include "PtrListOps.H"
|
||||
#include "foamVtkLineWriter.H"
|
||||
#include "foamVtkIndPatchWriter.H"
|
||||
#include "syncTools.H"
|
||||
#include "OBJstream.H"
|
||||
|
||||
using namespace Foam;
|
||||
@ -128,6 +130,8 @@ int main(int argc, char *argv[])
|
||||
meshDefDict.add("emptyPatch", patchName, true);
|
||||
}
|
||||
|
||||
// Preliminary checks
|
||||
#include "checkPatchTopology.H"
|
||||
|
||||
// Create
|
||||
faMesh aMesh(mesh, meshDefDict);
|
||||
|
||||
Reference in New Issue
Block a user