checkTools.C
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) 2015-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "checkTools.H"
30 #include "polyMesh.H"
31 #include "globalMeshData.H"
32 #include "hexMatcher.H"
33 #include "wedgeMatcher.H"
34 #include "prismMatcher.H"
35 #include "pyrMatcher.H"
36 #include "tetWedgeMatcher.H"
37 #include "tetMatcher.H"
38 #include "IOmanip.H"
39 #include "OFstream.H"
40 #include "pointSet.H"
41 #include "faceSet.H"
42 #include "cellSet.H"
43 #include "Time.H"
44 #include "coordSetWriter.H"
45 #include "surfaceWriter.H"
46 #include "syncTools.H"
47 #include "globalIndex.H"
48 #include "PatchTools.H"
49 #include "functionObject.H"
50 
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52 
53 void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
54 {
55  Info<< "Mesh stats " << mesh.regionName() << nl
56  << " points: "
57  << returnReduce(mesh.points().size(), sumOp<label>()) << nl;
58 
59 
60  // Count number of internal points (-1 if not sorted; 0 if no internal
61  // points)
62  const label minInt = returnReduce(mesh.nInternalPoints(), minOp<label>());
63  const label maxInt = returnReduce(mesh.nInternalPoints(), maxOp<label>());
64 
65  if (minInt == -1 && maxInt > 0)
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  else if (minInt != -1)
73  {
74  // Assume all sorted
75  label nInternalPoints = returnReduce
76  (
77  mesh.nInternalPoints(),
78  sumOp<label>()
79  );
80  Info<< " internal points: " << nInternalPoints << nl;
81  }
82 
83  if (allTopology && (minInt != -1))
84  {
85  label nEdges = returnReduce(mesh.nEdges(), sumOp<label>());
86  label nInternalEdges = returnReduce
87  (
88  mesh.nInternalEdges(),
89  sumOp<label>()
90  );
91  label nInternal1Edges = returnReduce
92  (
93  mesh.nInternal1Edges(),
94  sumOp<label>()
95  );
96  label nInternal0Edges = returnReduce
97  (
98  mesh.nInternal0Edges(),
99  sumOp<label>()
100  );
101 
102  Info<< " edges: " << nEdges << nl
103  << " internal edges: " << nInternalEdges << nl
104  << " internal edges using one boundary point: "
105  << nInternal1Edges-nInternal0Edges << nl
106  << " internal edges using two boundary points: "
107  << nInternalEdges-nInternal1Edges << nl;
108  }
109 
110  label nFaces = returnReduce(mesh.faces().size(), sumOp<label>());
111  label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>());
112  label nCells = returnReduce(mesh.cells().size(), sumOp<label>());
113  label nPatches = mesh.boundaryMesh().size();
114 
115  Info<< " faces: " << nFaces << nl
116  << " internal faces: " << nIntFaces << nl
117  << " cells: " << nCells << nl
118  << " faces per cell: "
119  << (scalar(nFaces) + scalar(nIntFaces))/max(1, nCells) << nl
120  << " boundary patches: ";
121 
122  if (Pstream::parRun())
123  {
124  // Number of global patches and min-max range of total patches
125  Info<< mesh.boundaryMesh().nNonProcessor() << ' '
126  << returnReduce(labelMinMax(nPatches), minMaxOp<label>()) << nl;
127  }
128  else
129  {
130  Info<< nPatches << nl;
131  }
132 
133  Info<< " point zones: " << mesh.pointZones().size() << nl
134  << " face zones: " << mesh.faceZones().size() << nl
135  << " cell zones: " << mesh.cellZones().size() << nl
136  << endl;
137 
138  // Construct shape recognizers
139  prismMatcher prism;
140  wedgeMatcher wedge;
141  tetWedgeMatcher tetWedge;
142 
143  // Counters for different cell types
144  label nHex = 0;
145  label nWedge = 0;
146  label nPrism = 0;
147  label nPyr = 0;
148  label nTet = 0;
149  label nTetWedge = 0;
150  label nUnknown = 0;
151 
152  Map<label> polyhedralFaces;
153 
154  for (label celli = 0; celli < mesh.nCells(); celli++)
155  {
156  if (hexMatcher::test(mesh, celli))
157  {
158  nHex++;
159  }
160  else if (tetMatcher::test(mesh, celli))
161  {
162  nTet++;
163  }
164  else if (pyrMatcher::test(mesh, celli))
165  {
166  nPyr++;
167  }
168  else if (prism.isA(mesh, celli))
169  {
170  nPrism++;
171  }
172  else if (wedge.isA(mesh, celli))
173  {
174  nWedge++;
175  }
176  else if (tetWedge.isA(mesh, celli))
177  {
178  nTetWedge++;
179  }
180  else
181  {
182  nUnknown++;
183  polyhedralFaces(mesh.cells()[celli].size())++;
184  }
185  }
186 
187  reduce(nHex,sumOp<label>());
188  reduce(nPrism,sumOp<label>());
189  reduce(nWedge,sumOp<label>());
190  reduce(nPyr,sumOp<label>());
191  reduce(nTetWedge,sumOp<label>());
192  reduce(nTet,sumOp<label>());
193  reduce(nUnknown,sumOp<label>());
194 
195  Info<< "Overall number of cells of each type:" << nl
196  << " hexahedra: " << nHex << nl
197  << " prisms: " << nPrism << nl
198  << " wedges: " << nWedge << nl
199  << " pyramids: " << nPyr << nl
200  << " tet wedges: " << nTetWedge << nl
201  << " tetrahedra: " << nTet << nl
202  << " polyhedra: " << nUnknown
203  << endl;
204 
205  if (nUnknown > 0)
206  {
207  Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>());
208 
209  Info<< " Breakdown of polyhedra by number of faces:" << nl
210  << " faces" << " number of cells" << endl;
211 
212  const labelList sortedKeys = polyhedralFaces.sortedToc();
213 
214  forAll(sortedKeys, keyi)
215  {
216  const label nFaces = sortedKeys[keyi];
217 
218  Info<< setf(std::ios::right) << setw(13)
219  << nFaces << " " << polyhedralFaces[nFaces] << nl;
220  }
221  }
222 
223  Info<< endl;
224 }
225 
226 
228 (
229  const polyMesh& mesh,
230  surfaceWriter& writer,
231  const word& name,
232  const indirectPrimitivePatch& setPatch,
233  const fileName& outputDir
234 )
235 {
236  writer.open
237  (
238  setPatch.localPoints(),
239  setPatch.localFaces(),
240  (outputDir / name)
241  );
242 
243  writer.write();
244  writer.clear();
245 }
246 
247 
249 (
250  surfaceWriter& writer,
251  const faceSet& set
252 )
253 {
254  const polyMesh& mesh = refCast<const polyMesh>(set.db());
255 
256  const indirectPrimitivePatch setPatch
257  (
258  IndirectList<face>(mesh.faces(), set.sortedToc()),
259  mesh.points()
260  );
261 
262  fileName outputDir
263  (
264  set.time().globalPath()
265  / functionObject::outputPrefix
266  / mesh.pointsInstance()
267  / set.name()
268  );
269  outputDir.clean(); // Remove unneeded ".."
270 
271  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
272 }
273 
274 
276 (
277  surfaceWriter& writer,
278  const cellSet& set
279 )
280 {
281  const polyMesh& mesh = refCast<const polyMesh>(set.db());
282  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
283 
284 
285  // Determine faces on outside of cellSet
286  bitSet isInSet(mesh.nCells());
287  for (const label celli : set)
288  {
289  isInSet.set(celli);
290  }
291 
292 
293  boolList bndInSet(mesh.nBoundaryFaces());
294  forAll(pbm, patchi)
295  {
296  const polyPatch& pp = pbm[patchi];
297  const labelList& fc = pp.faceCells();
298  forAll(fc, i)
299  {
300  bndInSet[pp.start()+i-mesh.nInternalFaces()] = isInSet[fc[i]];
301  }
302  }
303  syncTools::swapBoundaryFaceList(mesh, bndInSet);
304 
305 
306  DynamicList<label> outsideFaces(3*set.size());
307  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
308  {
309  const bool ownVal = isInSet[mesh.faceOwner()[facei]];
310  const bool neiVal = isInSet[mesh.faceNeighbour()[facei]];
311 
312  if (ownVal != neiVal)
313  {
314  outsideFaces.append(facei);
315  }
316  }
317 
318 
319  forAll(pbm, patchi)
320  {
321  const polyPatch& pp = pbm[patchi];
322  const labelList& fc = pp.faceCells();
323  if (pp.coupled())
324  {
325  forAll(fc, i)
326  {
327  label facei = pp.start()+i;
328 
329  const bool neiVal = bndInSet[facei-mesh.nInternalFaces()];
330  if (isInSet[fc[i]] && !neiVal)
331  {
332  outsideFaces.append(facei);
333  }
334  }
335  }
336  else
337  {
338  forAll(fc, i)
339  {
340  if (isInSet[fc[i]])
341  {
342  outsideFaces.append(pp.start()+i);
343  }
344  }
345  }
346  }
347 
348 
349  const indirectPrimitivePatch setPatch
350  (
351  IndirectList<face>(mesh.faces(), outsideFaces),
352  mesh.points()
353  );
354 
355  fileName outputDir
356  (
357  set.time().globalPath()
358  / functionObject::outputPrefix
359  / mesh.pointsInstance()
360  / set.name()
361  );
362  outputDir.clean(); // Remove unneeded ".."
363 
364  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
365 }
366 
367 
369 (
370  coordSetWriter& writer,
371  const pointSet& set
372 )
373 {
374  const polyMesh& mesh = refCast<const polyMesh>(set.db());
375 
376  labelField mergedIDs(set.sortedToc());
377  pointField mergedPts(mesh.points(), mergedIDs);
378 
379  if (Pstream::parRun())
380  {
381  // Note: we explicitly do not merge the points
382  // (mesh.globalData().mergePoints etc) since this might
383  // hide any synchronisation problem
384 
385  // Renumber local ids -> global ids
386  globalIndex(mesh.nPoints()).inplaceToGlobal(mergedIDs);
387 
388  globalIndex gatherer(globalIndex::gatherOnly{}, mergedIDs.size());
389  gatherer.gatherInplace(mergedIDs);
390  gatherer.gatherInplace(mergedPts);
391  }
392 
393 
394  // Write with pointID
395  if (Pstream::master())
396  {
397  coordSet coords(set.name(), "distance", mergedPts, mag(mergedPts));
398 
399  // Output. E.g. pointSet p0 -> postProcessing/<time>/p0.vtk
400 
401  fileName outputPath
402  (
403  set.time().globalPath()
404  / functionObject::outputPrefix
405  / mesh.pointsInstance()
406  / set.name()
407  );
408  outputPath.clean(); // Remove unneeded ".."
409 
410  writer.open(coords, outputPath);
411  writer.nFields(1);
412  writer.write("pointID", mergedIDs);
413  writer.close(true);
414  }
415 }
416 
417 
418 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:396
const polyBoundaryMesh & pbm
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/"finiteArea-edgesCentres"))
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
void mergeAndWrite(const polyMesh &mesh, surfaceWriter &writer, const word &name, const indirectPrimitivePatch &setPatch, const fileName &outputDir)
Generate merged surface on master and write. Needs input patch.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
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.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:169
MinMax< label > labelMinMax
A label min/max range.
Definition: MinMax.H:93
Istream and Ostream manipulators taking arguments.
#define WarningInFunction
Report a warning using Foam::Warning.
void printMeshStats(const polyMesh &mesh, const bool allTopology)
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.
List< label > sortedToc(const UList< bool > &bools)
Return the (sorted) values corresponding to &#39;true&#39; entries.
Definition: BitOps.C:195
messageStream Info
Information stream (stdout output on master, null elsewhere)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
List< label > labelList
A List of labels.
Definition: List.H:62
List< bool > boolList
A List of bools.
Definition: List.H:60
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())