checkPatchTopology.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
12 
13 Description
14  Check topology of poly patches used for finite-area.
15 
16 Input
17  mesh (polyMesh)
18  meshDefDict (system/faMeshDefintion)
19 
20 \*---------------------------------------------------------------------------*/
21 
22 // Preliminary checks
23 {
24  typedef typename uindirectPrimitivePatch::surfaceTopo TopoType;
25 
26  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
27 
28  wordRes polyPatchNames;
29  meshDefDict.readIfPresent("polyMeshPatches", polyPatchNames);
30 
31  const labelList patchIDs
32  (
33  pbm.indices(polyPatchNames, true) // useGroups
34  );
35 
36  label nFaceLabels = 0;
37  for (const label patchi : patchIDs)
38  {
39  nFaceLabels += pbm[patchi].size();
40  }
41 
43 
44  nFaceLabels = 0;
45  for (const label patchi : patchIDs)
46  {
47  for (const label facei : pbm[patchi].range())
48  {
49  faceLabels[nFaceLabels] = facei;
50  ++nFaceLabels;
51  }
52  }
53 
55  (
56  UIndirectList<face>(mesh.faces(), faceLabels),
57  mesh.points()
58  );
59 
60  // Non-manifold
61  labelHashSet badEdges(pp.nEdges()/20);
62 
63  labelHashSet* pointSetPtr = nullptr;
65 
66  bool foundError = false;
67 
68  if (returnReduceAnd(pp.empty()))
69  {
70  // Empty
71  }
72  else if (UPstream::parRun())
73  {
74  const labelList meshEdges
75  (
76  pp.meshEdges(mesh.edges(), mesh.pointEdges())
77  );
78 
79  // Parallel - use mesh edges
80  // - no check for point-pinch
81  // - no check for consistent orientation (if that is posible to
82  // check?)
83 
84  // Count number of edge/face connections (globally)
85  labelList nEdgeConnections(mesh.nEdges(), Zero);
86 
87  const labelListList& edgeFaces = pp.edgeFaces();
88 
89  forAll(edgeFaces, edgei)
90  {
91  nEdgeConnections[meshEdges[edgei]] = edgeFaces[edgei].size();
92  }
93 
94  // Synchronise across coupled edges
95  syncTools::syncEdgeList
96  (
97  mesh,
98  nEdgeConnections,
99  plusEqOp<label>(),
100  label(0) // null value
101  );
102 
103  label labelTyp = TopoType::MANIFOLD;
104  forAll(meshEdges, edgei)
105  {
106  const label meshEdgei = meshEdges[edgei];
107  const label numNbrs = nEdgeConnections[meshEdgei];
108  if (numNbrs == 1)
109  {
110  //if (pointSetPtr) pointSetPtr->insert(mesh.edges()[meshEdgei]);
111  labelTyp = max(labelTyp, TopoType::OPEN);
112  }
113  else if (numNbrs == 0 || numNbrs > 2)
114  {
115  if (pointSetPtr) pointSetPtr->insert(mesh.edges()[meshEdgei]);
116  if (badEdgesPtr) badEdgesPtr->insert(edgei);
117  labelTyp = max(labelTyp, TopoType::ILLEGAL);
118  }
119  }
120  reduce(labelTyp, maxOp<label>());
121 
122  foundError = (labelTyp == TopoType::ILLEGAL);
123  }
124  else
125  {
126  const TopoType pTyp = pp.surfaceType(badEdgesPtr);
127 
128  foundError = (pTyp == TopoType::ILLEGAL);
129  }
130 
131  if (foundError)
132  {
133  edgeList dumpEdges(pp.edges(), badEdges.sortedToc());
134 
135  vtk::lineWriter writer
136  (
137  pp.localPoints(),
138  dumpEdges,
139  fileName
140  (
141  mesh.time().globalPath()
142  / ("faMesh-construct.illegalEdges")
143  )
144  );
145 
146  writer.writeGeometry();
147 
148  // CellData
149  writer.beginCellData();
150  writer.writeProcIDs();
151 
152  Info<< "Wrote "
153  << returnReduce(dumpEdges.size(), sumOp<label>())
154  << " bad edges: " << writer.output().name() << nl;
155  writer.close();
156  }
157 }
158 
159 // ************************************************************************* //
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const polyBoundaryMesh & pbm
IOdictionary & meshDefDict
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/"finiteArea-edgesCentres"))
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
labelList faceLabels(nFaceLabels)
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
scalar range
labelHashSet badEdges(pp.nEdges()/20)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
dynamicFvMesh & mesh
labelHashSet * pointSetPtr
wordRes polyPatchNames
label nFaceLabels
labelHashSet * badEdgesPtr
bool foundError
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
messageStream Info
Information stream (stdout output on master, null elsewhere)
List< label > labelList
A List of labels.
Definition: List.H:62
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127