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-2021 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 
46 
47 void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology)
48 {
49  Info<< "Mesh stats" << nl
50  << " points: "
51  << returnReduce(mesh.points().size(), sumOp<label>()) << nl;
52 
53  label nInternalPoints = returnReduce
54  (
55  mesh.nInternalPoints(),
56  sumOp<label>()
57  );
58 
59  if (nInternalPoints != -Pstream::nProcs())
60  {
61  Info<< " internal points: " << nInternalPoints << nl;
62 
63  if (returnReduce(mesh.nInternalPoints(), minOp<label>()) == -1)
64  {
66  << "Some processors have their points sorted into internal"
67  << " and external and some do not." << endl
68  << "This can cause problems later on." << endl;
69  }
70  }
71 
72  if (allTopology && nInternalPoints != -Pstream::nProcs())
73  {
74  label nEdges = returnReduce(mesh.nEdges(), sumOp<label>());
75  label nInternalEdges = returnReduce
76  (
77  mesh.nInternalEdges(),
78  sumOp<label>()
79  );
80  label nInternal1Edges = returnReduce
81  (
82  mesh.nInternal1Edges(),
83  sumOp<label>()
84  );
85  label nInternal0Edges = returnReduce
86  (
87  mesh.nInternal0Edges(),
88  sumOp<label>()
89  );
90 
91  Info<< " edges: " << nEdges << nl
92  << " internal edges: " << nInternalEdges << nl
93  << " internal edges using one boundary point: "
94  << nInternal1Edges-nInternal0Edges << nl
95  << " internal edges using two boundary points: "
96  << nInternalEdges-nInternal1Edges << nl;
97  }
98 
99  label nFaces = returnReduce(mesh.faces().size(), sumOp<label>());
100  label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>());
101  label nCells = returnReduce(mesh.cells().size(), sumOp<label>());
102 
103  Info<< " faces: " << nFaces << nl
104  << " internal faces: " << nIntFaces << nl
105  << " cells: " << nCells << nl
106  << " faces per cell: "
107  << scalar(nFaces + nIntFaces)/max(1, nCells) << nl
108  << " boundary patches: " << mesh.boundaryMesh().size() << nl
109  << " point zones: " << mesh.pointZones().size() << nl
110  << " face zones: " << mesh.faceZones().size() << nl
111  << " cell zones: " << mesh.cellZones().size() << nl
112  << endl;
113 
114  // Construct shape recognisers
115  hexMatcher hex;
116  prismMatcher prism;
117  wedgeMatcher wedge;
118  pyrMatcher pyr;
119  tetWedgeMatcher tetWedge;
120  tetMatcher tet;
121 
122  // Counters for different cell types
123  label nHex = 0;
124  label nWedge = 0;
125  label nPrism = 0;
126  label nPyr = 0;
127  label nTet = 0;
128  label nTetWedge = 0;
129  label nUnknown = 0;
130 
131  Map<label> polyhedralFaces;
132 
133  for (label celli = 0; celli < mesh.nCells(); celli++)
134  {
135  if (hex.isA(mesh, celli))
136  {
137  nHex++;
138  }
139  else if (tet.isA(mesh, celli))
140  {
141  nTet++;
142  }
143  else if (pyr.isA(mesh, celli))
144  {
145  nPyr++;
146  }
147  else if (prism.isA(mesh, celli))
148  {
149  nPrism++;
150  }
151  else if (wedge.isA(mesh, celli))
152  {
153  nWedge++;
154  }
155  else if (tetWedge.isA(mesh, celli))
156  {
157  nTetWedge++;
158  }
159  else
160  {
161  nUnknown++;
162  polyhedralFaces(mesh.cells()[celli].size())++;
163  }
164  }
165 
166  reduce(nHex,sumOp<label>());
167  reduce(nPrism,sumOp<label>());
168  reduce(nWedge,sumOp<label>());
169  reduce(nPyr,sumOp<label>());
170  reduce(nTetWedge,sumOp<label>());
171  reduce(nTet,sumOp<label>());
172  reduce(nUnknown,sumOp<label>());
173 
174  Info<< "Overall number of cells of each type:" << nl
175  << " hexahedra: " << nHex << nl
176  << " prisms: " << nPrism << nl
177  << " wedges: " << nWedge << nl
178  << " pyramids: " << nPyr << nl
179  << " tet wedges: " << nTetWedge << nl
180  << " tetrahedra: " << nTet << nl
181  << " polyhedra: " << nUnknown
182  << endl;
183 
184  if (nUnknown > 0)
185  {
186  Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>());
187 
188  Info<< " Breakdown of polyhedra by number of faces:" << nl
189  << " faces" << " number of cells" << endl;
190 
191  const labelList sortedKeys = polyhedralFaces.sortedToc();
192 
193  forAll(sortedKeys, keyI)
194  {
195  const label nFaces = sortedKeys[keyI];
196 
197  Info<< setf(std::ios::right) << setw(13)
198  << nFaces << " " << polyhedralFaces[nFaces] << nl;
199  }
200  }
201 
202  Info<< endl;
203 }
204 
205 
207 (
208  const polyMesh& mesh,
209  const surfaceWriter& writer,
210  const word& name,
211  const indirectPrimitivePatch setPatch,
212  const fileName& outputDir
213 )
214 {
215  if (Pstream::parRun())
216  {
217  labelList pointToGlobal;
218  labelList uniqueMeshPointLabels;
219  autoPtr<globalIndex> globalPoints;
220  autoPtr<globalIndex> globalFaces;
221  faceList mergedFaces;
222  pointField mergedPoints;
224  (
225  mesh,
226  setPatch.localFaces(),
227  setPatch.meshPoints(),
228  setPatch.meshPointMap(),
229 
230  pointToGlobal,
231  uniqueMeshPointLabels,
232  globalPoints,
233  globalFaces,
234 
235  mergedFaces,
236  mergedPoints
237  );
238 
239  // Write
240  if (Pstream::master())
241  {
242  writer.write(outputDir, name, mergedPoints, mergedFaces);
243  }
244  }
245  else
246  {
247  writer.write
248  (
249  outputDir,
250  name,
251  setPatch.localPoints(),
252  setPatch.localFaces()
253  );
254  }
255 }
256 
257 
259 (
260  const surfaceWriter& writer,
261  const faceSet& set
262 )
263 {
264  const polyMesh& mesh = refCast<const polyMesh>(set.db());
265 
266  const indirectPrimitivePatch setPatch
267  (
268  IndirectList<face>(mesh.faces(), set.sortedToc()),
269  mesh.points()
270  );
271 
272  fileName outputDir
273  (
274  set.time().globalPath()
275  /functionObjects::writeFile::outputPrefix
276  /mesh.pointsInstance()
277  /set.name()
278  );
279 
280  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
281 }
282 
283 
285 (
286  const surfaceWriter& writer,
287  const cellSet& set
288 )
289 {
290  const polyMesh& mesh = refCast<const polyMesh>(set.db());
291  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
292 
293 
294  // Determine faces on outside of cellSet
295  PackedBoolList isInSet(mesh.nCells());
296  forAllConstIter(cellSet, set, iter)
297  {
298  isInSet[iter.key()] = true;
299  }
300 
301 
302  boolList bndInSet(mesh.nFaces()-mesh.nInternalFaces());
303  forAll(pbm, patchi)
304  {
305  const polyPatch& pp = pbm[patchi];
306  const labelList& fc = pp.faceCells();
307  forAll(fc, i)
308  {
309  bndInSet[pp.start()+i-mesh.nInternalFaces()] = isInSet[fc[i]];
310  }
311  }
312  syncTools::swapBoundaryFaceList(mesh, bndInSet);
313 
314 
315  DynamicList<label> outsideFaces(3*set.size());
316  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
317  {
318  bool ownVal = isInSet[mesh.faceOwner()[facei]];
319  bool neiVal = isInSet[mesh.faceNeighbour()[facei]];
320 
321  if (ownVal != neiVal)
322  {
323  outsideFaces.append(facei);
324  }
325  }
326 
327 
328  forAll(pbm, patchi)
329  {
330  const polyPatch& pp = pbm[patchi];
331  const labelList& fc = pp.faceCells();
332  if (pp.coupled())
333  {
334  forAll(fc, i)
335  {
336  label facei = pp.start()+i;
337 
338  bool neiVal = bndInSet[facei-mesh.nInternalFaces()];
339  if (isInSet[fc[i]] && !neiVal)
340  {
341  outsideFaces.append(facei);
342  }
343  }
344  }
345  else
346  {
347  forAll(fc, i)
348  {
349  if (isInSet[fc[i]])
350  {
351  outsideFaces.append(pp.start()+i);
352  }
353  }
354  }
355  }
356 
357 
358  const indirectPrimitivePatch setPatch
359  (
360  IndirectList<face>(mesh.faces(), outsideFaces),
361  mesh.points()
362  );
363 
364  fileName outputDir
365  (
366  set.time().path()
367  / (Pstream::parRun() ? ".." : "")
368  / "postProcessing"
369  / mesh.pointsInstance()
370  / set.name()
371  );
372  outputDir.clean();
373 
374  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
375 }
376 
377 
379 (
380  const setWriter<scalar>& writer,
381  const pointSet& set
382 )
383 {
384  const polyMesh& mesh = refCast<const polyMesh>(set.db());
385 
386  pointField mergedPts;
387  labelList mergedIDs;
388 
389  if (Pstream::parRun())
390  {
391  // Note: we explicitly do not merge the points
392  // (mesh.globalData().mergePoints etc) since this might
393  // hide any synchronisation problem
394 
395  globalIndex globalNumbering(mesh.nPoints());
396 
397  mergedPts.setSize(returnReduce(set.size(), sumOp<label>()));
398  mergedIDs.setSize(mergedPts.size());
399 
400  labelList setPointIDs(set.sortedToc());
401 
402  // Get renumbered local data
403  pointField myPoints(mesh.points(), setPointIDs);
404  labelList myIDs(setPointIDs.size());
405  forAll(setPointIDs, i)
406  {
407  myIDs[i] = globalNumbering.toGlobal(setPointIDs[i]);
408  }
409 
410  if (Pstream::master())
411  {
412  // Insert master data first
413  label pOffset = 0;
414  SubList<point>(mergedPts, myPoints.size(), pOffset) = myPoints;
415  SubList<label>(mergedIDs, myIDs.size(), pOffset) = myIDs;
416  pOffset += myPoints.size();
417 
418  // Receive slave ones
419  for (int slave=1; slave<Pstream::nProcs(); slave++)
420  {
421  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
422 
423  pointField slavePts(fromSlave);
424  labelList slaveIDs(fromSlave);
425 
426  SubList<point>(mergedPts, slavePts.size(), pOffset) = slavePts;
427  SubList<label>(mergedIDs, slaveIDs.size(), pOffset) = slaveIDs;
428  pOffset += slaveIDs.size();
429  }
430  }
431  else
432  {
433  // Construct processor stream with estimate of size. Could
434  // be improved.
435  OPstream toMaster
436  (
437  Pstream::commsTypes::scheduled,
438  Pstream::masterNo(),
439  myPoints.byteSize() + myIDs.byteSize()
440  );
441  toMaster << myPoints << myIDs;
442  }
443  }
444  else
445  {
446  mergedIDs = set.sortedToc();
447  mergedPts = pointField(mesh.points(), mergedIDs);
448  }
449 
450 
451  // Write with scalar pointID
452  if (Pstream::master())
453  {
454  scalarField scalarPointIDs(mergedIDs.size());
455  forAll(mergedIDs, i)
456  {
457  scalarPointIDs[i] = 1.0*mergedIDs[i];
458  }
459 
460  coordSet points(set.name(), "distance", mergedPts, mag(mergedPts));
461 
462  List<const scalarField*> flds(1, &scalarPointIDs);
463 
464  wordList fldNames(1, "pointID");
465 
466  // Output e.g. pointSet p0 to
467  // postProcessing/<time>/p0.vtk
468  fileName outputDir
469  (
470  set.time().path()
471  / (Pstream::parRun() ? ".." : "")
472  / "postProcessing"
473  / mesh.pointsInstance()
474  // set.name()
475  );
476  outputDir.clean();
477  mkDir(outputDir);
478 
479  fileName outputFile(outputDir/writer.getFileName(points, wordList()));
480  // fileName outputFile(outputDir/set.name());
481 
482  OFstream os(outputFile);
483 
484  writer.write(points, fldNames, flds, os);
485  }
486 }
487 
488 
489 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
IOstream & hex(IOstream &io)
Definition: IOstream.H:561
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.
List< face > faceList
Definition: faceListFwd.H:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
Foam::indirectPrimitivePatch.
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
const pointField & points
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.
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
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
volScalarField scalarField(fieldObject, mesh)
Istream and Ostream manipulators taking arguments.
static const char nl
Definition: Ostream.H:260
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
void printMeshStats(const polyMesh &mesh, const bool allTopology)
List< word > wordList
A List of words.
Definition: fileName.H:54
void setSize(const label)
Reset size of List.
Definition: List.C:281
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
fileName path(UMean.rootPath()/UMean.caseName()/functionObjects::writeFile::outputPrefix/"graphs"/UMean.instance())