checkTools.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2015-2023 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "checkTools.H"
27 #include "polyMesh.H"
28 #include "globalMeshData.H"
29 #include "hexMatcher.H"
30 #include "wedgeMatcher.H"
31 #include "prismMatcher.H"
32 #include "pyrMatcher.H"
33 #include "tetWedgeMatcher.H"
34 #include "tetMatcher.H"
35 #include "IOmanip.H"
36 #include "pointSet.H"
37 #include "faceSet.H"
38 #include "cellSet.H"
39 #include "Time.H"
40 #include "surfaceWriter.H"
41 #include "syncTools.H"
42 #include "globalIndex.H"
43 #include "PatchTools.H"
44 #include "writeFile.H"
45 #include "coordSet.H"
46 
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 
49 void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
50 {
51  Info<< "Mesh stats" << nl
52  << " points: "
53  << returnReduce(mesh.points().size(), sumOp<label>()) << nl;
54 
55  label nInternalPoints = returnReduce
56  (
57  mesh.nInternalPoints(),
58  sumOp<label>()
59  );
60 
61  if (nInternalPoints != -Pstream::nProcs())
62  {
63  Info<< " internal points: " << nInternalPoints << nl;
64 
65  if (returnReduce(mesh.nInternalPoints(), minOp<label>()) == -1)
66  {
68  << "Some processors have their points sorted into internal"
69  << " and external and some do not." << endl
70  << "This can cause problems later on." << endl;
71  }
72  }
73 
74  if (allTopology && nInternalPoints != -Pstream::nProcs())
75  {
76  label nEdges = returnReduce(mesh.nEdges(), sumOp<label>());
77  label nInternalEdges = returnReduce
78  (
79  mesh.nInternalEdges(),
80  sumOp<label>()
81  );
82  label nInternal1Edges = returnReduce
83  (
84  mesh.nInternal1Edges(),
85  sumOp<label>()
86  );
87  label nInternal0Edges = returnReduce
88  (
89  mesh.nInternal0Edges(),
90  sumOp<label>()
91  );
92 
93  Info<< " edges: " << nEdges << nl
94  << " internal edges: " << nInternalEdges << nl
95  << " internal edges using one boundary point: "
96  << nInternal1Edges-nInternal0Edges << nl
97  << " internal edges using two boundary points: "
98  << nInternalEdges-nInternal1Edges << nl;
99  }
100 
101  label nFaces = returnReduce(mesh.faces().size(), sumOp<label>());
102  label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>());
103  label nCells = returnReduce(mesh.cells().size(), sumOp<label>());
104 
105  Info<< " faces: " << nFaces << nl
106  << " internal faces: " << nIntFaces << nl
107  << " cells: " << nCells << nl
108  << " faces per cell: "
109  << scalar(nFaces + nIntFaces)/max(1, nCells) << nl
110  << " boundary patches: " << mesh.boundaryMesh().size() << nl
111  << " point zones: " << mesh.pointZones().size() << nl
112  << " face zones: " << mesh.faceZones().size() << nl
113  << " cell zones: " << mesh.cellZones().size() << nl
114  << endl;
115 
116  // Construct shape recognisers
117  hexMatcher hex;
118  prismMatcher prism;
119  wedgeMatcher wedge;
120  pyrMatcher pyr;
121  tetWedgeMatcher tetWedge;
122  tetMatcher tet;
123 
124  // Counters for different cell types
125  label nHex = 0;
126  label nWedge = 0;
127  label nPrism = 0;
128  label nPyr = 0;
129  label nTet = 0;
130  label nTetWedge = 0;
131  label nUnknown = 0;
132 
133  Map<label> polyhedralFaces;
134 
135  for (label celli = 0; celli < mesh.nCells(); celli++)
136  {
137  if (hex.isA(mesh, celli))
138  {
139  nHex++;
140  }
141  else if (tet.isA(mesh, celli))
142  {
143  nTet++;
144  }
145  else if (pyr.isA(mesh, celli))
146  {
147  nPyr++;
148  }
149  else if (prism.isA(mesh, celli))
150  {
151  nPrism++;
152  }
153  else if (wedge.isA(mesh, celli))
154  {
155  nWedge++;
156  }
157  else if (tetWedge.isA(mesh, celli))
158  {
159  nTetWedge++;
160  }
161  else
162  {
163  nUnknown++;
164  polyhedralFaces(mesh.cells()[celli].size())++;
165  }
166  }
167 
168  reduce(nHex,sumOp<label>());
169  reduce(nPrism,sumOp<label>());
170  reduce(nWedge,sumOp<label>());
171  reduce(nPyr,sumOp<label>());
172  reduce(nTetWedge,sumOp<label>());
173  reduce(nTet,sumOp<label>());
174  reduce(nUnknown,sumOp<label>());
175 
176  Info<< "Overall number of cells of each type:" << nl
177  << " hexahedra: " << nHex << nl
178  << " prisms: " << nPrism << nl
179  << " wedges: " << nWedge << nl
180  << " pyramids: " << nPyr << nl
181  << " tet wedges: " << nTetWedge << nl
182  << " tetrahedra: " << nTet << nl
183  << " polyhedra: " << nUnknown
184  << endl;
185 
186  if (nUnknown > 0)
187  {
188  Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>());
189 
190  Info<< " Breakdown of polyhedra by number of faces:" << nl
191  << " faces" << " number of cells" << endl;
192 
193  const labelList sortedKeys = polyhedralFaces.sortedToc();
194 
195  forAll(sortedKeys, keyI)
196  {
197  const label nFaces = sortedKeys[keyI];
198 
199  Info<< setf(std::ios::right) << setw(13)
200  << nFaces << " " << polyhedralFaces[nFaces] << nl;
201  }
202  }
203 
204  Info<< endl;
205 }
206 
207 
209 (
210  const polyMesh& mesh,
211  const surfaceWriter& writer,
212  const word& name,
213  const indirectPrimitivePatch setPatch,
214  const fileName& outputDir
215 )
216 {
217  if (Pstream::parRun())
218  {
219  labelList pointToGlobal;
220  labelList uniqueMeshPointLabels;
221  autoPtr<globalIndex> globalPoints;
222  autoPtr<globalIndex> globalFaces;
223  faceList mergedFaces;
224  pointField mergedPoints;
226  (
227  mesh,
228  setPatch.localFaces(),
229  setPatch.meshPoints(),
230  setPatch.meshPointMap(),
231 
232  pointToGlobal,
233  uniqueMeshPointLabels,
234  globalPoints,
235  globalFaces,
236 
237  mergedFaces,
238  mergedPoints
239  );
240 
241  // Write
242  if (Pstream::master())
243  {
244  writer.write(outputDir, name, mergedPoints, mergedFaces);
245  }
246  }
247  else
248  {
249  writer.write
250  (
251  outputDir,
252  name,
253  setPatch.localPoints(),
254  setPatch.localFaces()
255  );
256  }
257 }
258 
259 
260 Foam::fileName Foam::checkMeshOutputDir(const polyMesh& mesh)
261 {
262  return
263  mesh.time().globalPath()
264  /functionObjects::writeFile::outputPrefix
265  /(
266  (mesh.name() != polyMesh::defaultRegion)
267  ? mesh.name()
268  : word::null
269  )
270  /"checkMesh"
271  /mesh.pointsInstance();
272 }
273 
274 
276 (
277  const surfaceWriter& writer,
278  const faceSet& set
279 )
280 {
281  const polyMesh& mesh = refCast<const polyMesh>(set.db());
282 
283  const indirectPrimitivePatch setPatch
284  (
285  IndirectList<face>(mesh.faces(), set.sortedToc()),
286  mesh.points()
287  );
288 
289  mergeAndWrite(mesh, writer, set.name(), setPatch, checkMeshOutputDir(mesh));
290 }
291 
292 
294 (
295  const surfaceWriter& writer,
296  const cellSet& set
297 )
298 {
299  const polyMesh& mesh = refCast<const polyMesh>(set.db());
300  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
301 
302 
303  // Determine faces on outside of cellSet
304  PackedBoolList isInSet(mesh.nCells());
305  forAllConstIter(cellSet, set, iter)
306  {
307  isInSet[iter.key()] = true;
308  }
309 
310 
311  boolList bndInSet(mesh.nFaces()-mesh.nInternalFaces());
312  forAll(pbm, patchi)
313  {
314  const polyPatch& pp = pbm[patchi];
315  const labelList& fc = pp.faceCells();
316  forAll(fc, i)
317  {
318  bndInSet[pp.start()+i-mesh.nInternalFaces()] = isInSet[fc[i]];
319  }
320  }
321  syncTools::swapBoundaryFaceList(mesh, bndInSet);
322 
323 
324  DynamicList<label> outsideFaces(3*set.size());
325  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
326  {
327  bool ownVal = isInSet[mesh.faceOwner()[facei]];
328  bool neiVal = isInSet[mesh.faceNeighbour()[facei]];
329 
330  if (ownVal != neiVal)
331  {
332  outsideFaces.append(facei);
333  }
334  }
335 
336 
337  forAll(pbm, patchi)
338  {
339  const polyPatch& pp = pbm[patchi];
340  const labelList& fc = pp.faceCells();
341  if (pp.coupled())
342  {
343  forAll(fc, i)
344  {
345  label facei = pp.start()+i;
346 
347  bool neiVal = bndInSet[facei-mesh.nInternalFaces()];
348  if (isInSet[fc[i]] && !neiVal)
349  {
350  outsideFaces.append(facei);
351  }
352  }
353  }
354  else
355  {
356  forAll(fc, i)
357  {
358  if (isInSet[fc[i]])
359  {
360  outsideFaces.append(pp.start()+i);
361  }
362  }
363  }
364  }
365 
366 
367  const indirectPrimitivePatch setPatch
368  (
369  IndirectList<face>(mesh.faces(), outsideFaces),
370  mesh.points()
371  );
372 
373  const fileName outputDir(checkMeshOutputDir(mesh));
374  outputDir.clean();
375 
376  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
377 }
378 
379 
381 (
382  const setWriter& writer,
383  const pointSet& set
384 )
385 {
386  const polyMesh& mesh = refCast<const polyMesh>(set.db());
387 
388  pointField mergedPts;
389  labelList mergedIDs;
390 
391  if (Pstream::parRun())
392  {
393  // Note: we explicitly do not merge the points
394  // (mesh.globalData().mergePoints etc) since this might
395  // hide any synchronisation problem
396 
397  globalIndex globalNumbering(mesh.nPoints());
398 
399  mergedPts.setSize(returnReduce(set.size(), sumOp<label>()));
400  mergedIDs.setSize(mergedPts.size());
401 
402  labelList setPointIDs(set.sortedToc());
403 
404  // Get renumbered local data
405  pointField myPoints(mesh.points(), setPointIDs);
406  labelList myIDs(setPointIDs.size());
407  forAll(setPointIDs, i)
408  {
409  myIDs[i] = globalNumbering.toGlobal(setPointIDs[i]);
410  }
411 
412  if (Pstream::master())
413  {
414  // Insert master data first
415  label pOffset = 0;
416  SubList<point>(mergedPts, myPoints.size(), pOffset) = myPoints;
417  SubList<label>(mergedIDs, myIDs.size(), pOffset) = myIDs;
418  pOffset += myPoints.size();
419 
420  // Receive slave ones
421  for (int slave=1; slave<Pstream::nProcs(); slave++)
422  {
423  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
424 
425  pointField slavePts(fromSlave);
426  labelList slaveIDs(fromSlave);
427 
428  SubList<point>(mergedPts, slavePts.size(), pOffset) = slavePts;
429  SubList<label>(mergedIDs, slaveIDs.size(), pOffset) = slaveIDs;
430  pOffset += slaveIDs.size();
431  }
432  }
433  else
434  {
435  // Construct processor stream with estimate of size. Could
436  // be improved.
437  OPstream toMaster
438  (
439  Pstream::commsTypes::scheduled,
440  Pstream::masterNo(),
441  myPoints.byteSize() + myIDs.byteSize()
442  );
443  toMaster << myPoints << myIDs;
444  }
445  }
446  else
447  {
448  mergedIDs = set.sortedToc();
449  mergedPts = pointField(mesh.points(), mergedIDs);
450  }
451 
452  // Write with scalar pointID
453  if (Pstream::master())
454  {
455  writer.write
456  (
457  checkMeshOutputDir(mesh),
458  set.name(),
459  coordSet(false, word::null, mergedPts),
460  "pointID",
461  scalarField(scalarList(mergedIDs))
462  );
463  }
464 }
465 
466 
467 // ************************************************************************* //
Istream and Ostream manipulators taking arguments.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
Tools for checking the mesh.
static void gatherAndMerge(const scalar mergeDist, const PrimitivePatch< FaceList, PointField > &p, Field< typename PrimitivePatch< FaceList, PointField >::PointType > &mergedPoints, List< typename PrimitivePatch< FaceList, PointField >::FaceType > &mergedFaces, labelList &pointMergeMap)
Gather points and faces onto master and merge into single patch.
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
volScalarField scalarField(fieldObject, mesh)
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:164
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
void mergeAndWrite(const polyMesh &mesh, const surfaceWriter &setWriter, const word &name, const indirectPrimitivePatch setPatch, const fileName &outputDir)
Generate merged surface on master and write. Needs input patch.
IOstream & hex(IOstream &io)
Definition: IOstream.H:561
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
void printMeshStats(const polyMesh &mesh, const bool allTopology)
Print mesh statistics.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
fileName checkMeshOutputDir(const polyMesh &mesh)
Output directory for sets and surfaces.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
List< face > faceList
Definition: faceListFwd.H:43
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
Foam::indirectPrimitivePatch.
static const char nl
Definition: Ostream.H:260