mergeAndWrite.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 "mergeAndWrite.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 
50 (
51  const polyMesh& mesh,
52  const bool allTopology
53 )
54 {
55  Info<< "Mesh stats" << nl
56  << " points: "
57  << returnReduce(mesh.points().size(), sumOp<label>()) << nl;
58 
59  label nInternalPoints = returnReduce
60  (
61  mesh.nInternalPoints(),
62  sumOp<label>()
63  );
64 
65  if (nInternalPoints != -Pstream::nProcs())
66  {
67  Info<< " internal points: " << nInternalPoints << nl;
68 
69  if (returnReduce(mesh.nInternalPoints(), minOp<label>()) == -1)
70  {
72  << "Some processors have their points sorted into internal"
73  << " and external and some do not." << endl
74  << "This can cause problems later on." << endl;
75  }
76  }
77 
78  if (allTopology && nInternalPoints != -Pstream::nProcs())
79  {
80  label nEdges = returnReduce(mesh.nEdges(), sumOp<label>());
81  label nInternalEdges = returnReduce
82  (
83  mesh.nInternalEdges(),
84  sumOp<label>()
85  );
86  label nInternal1Edges = returnReduce
87  (
88  mesh.nInternal1Edges(),
89  sumOp<label>()
90  );
91  label nInternal0Edges = returnReduce
92  (
93  mesh.nInternal0Edges(),
94  sumOp<label>()
95  );
96 
97  Info<< " edges: " << nEdges << nl
98  << " internal edges: " << nInternalEdges << nl
99  << " internal edges using one boundary point: "
100  << nInternal1Edges-nInternal0Edges << nl
101  << " internal edges using two boundary points: "
102  << nInternalEdges-nInternal1Edges << nl;
103  }
104 
105  label nFaces = returnReduce(mesh.faces().size(), sumOp<label>());
106  label nIntFaces = returnReduce(mesh.faceNeighbour().size(), sumOp<label>());
107  label nCells = returnReduce(mesh.cells().size(), sumOp<label>());
108 
109  Info<< " faces: " << nFaces << nl
110  << " internal faces: " << nIntFaces << nl
111  << " cells: " << nCells << nl
112  << " faces per cell: "
113  << scalar(nFaces + nIntFaces)/max(1, nCells) << nl
114  << " boundary patches: " << mesh.boundaryMesh().size() << nl
115  << " point zones: " << mesh.pointZones().size() << nl
116  << " face zones: " << mesh.faceZones().size() << nl
117  << " cell zones: " << mesh.cellZones().size() << nl
118  << endl;
119 
120  // Construct shape recognisers
121  hexMatcher hex;
122  prismMatcher prism;
123  wedgeMatcher wedge;
124  pyrMatcher pyr;
125  tetWedgeMatcher tetWedge;
126  tetMatcher tet;
127 
128  // Counters for different cell types
129  label nHex = 0;
130  label nWedge = 0;
131  label nPrism = 0;
132  label nPyr = 0;
133  label nTet = 0;
134  label nTetWedge = 0;
135  label nUnknown = 0;
136 
137  Map<label> polyhedralFaces;
138 
139  for (label celli = 0; celli < mesh.nCells(); celli++)
140  {
141  if (hex.isA(mesh, celli))
142  {
143  nHex++;
144  }
145  else if (tet.isA(mesh, celli))
146  {
147  nTet++;
148  }
149  else if (pyr.isA(mesh, celli))
150  {
151  nPyr++;
152  }
153  else if (prism.isA(mesh, celli))
154  {
155  nPrism++;
156  }
157  else if (wedge.isA(mesh, celli))
158  {
159  nWedge++;
160  }
161  else if (tetWedge.isA(mesh, celli))
162  {
163  nTetWedge++;
164  }
165  else
166  {
167  nUnknown++;
168  polyhedralFaces(mesh.cells()[celli].size())++;
169  }
170  }
171 
172  reduce(nHex,sumOp<label>());
173  reduce(nPrism,sumOp<label>());
174  reduce(nWedge,sumOp<label>());
175  reduce(nPyr,sumOp<label>());
176  reduce(nTetWedge,sumOp<label>());
177  reduce(nTet,sumOp<label>());
178  reduce(nUnknown,sumOp<label>());
179 
180  Info<< "Overall number of cells of each type:" << nl
181  << " hexahedra: " << nHex << nl
182  << " prisms: " << nPrism << nl
183  << " wedges: " << nWedge << nl
184  << " pyramids: " << nPyr << nl
185  << " tet wedges: " << nTetWedge << nl
186  << " tetrahedra: " << nTet << nl
187  << " polyhedra: " << nUnknown
188  << endl;
189 
190  if (nUnknown > 0)
191  {
192  Pstream::mapCombineGather(polyhedralFaces, plusEqOp<label>());
193 
194  Info<< " Breakdown of polyhedra by number of faces:" << nl
195  << " faces" << " number of cells" << endl;
196 
197  const labelList sortedKeys = polyhedralFaces.sortedToc();
198 
199  forAll(sortedKeys, keyI)
200  {
201  const label nFaces = sortedKeys[keyI];
202 
203  Info<< setf(std::ios::right) << setw(13)
204  << nFaces << " " << polyhedralFaces[nFaces] << nl;
205  }
206  }
207 
208  Info<< endl;
209 }
210 
211 
213 (
214  const polyMesh& mesh,
215  const surfaceWriter& writer,
216  const word& name,
217  const indirectPrimitivePatch setPatch,
218  const fileName& outputDir
219 )
220 {
221  if (Pstream::parRun())
222  {
223  labelList pointToGlobal;
224  labelList uniqueMeshPointLabels;
226  autoPtr<globalIndex> globalFaces;
227  faceList mergedFaces;
228  pointField mergedPoints;
230  (
231  mesh,
232  setPatch.localFaces(),
233  setPatch.meshPoints(),
234  setPatch.meshPointMap(),
235 
236  pointToGlobal,
237  uniqueMeshPointLabels,
238  globalPoints,
239  globalFaces,
240 
241  mergedFaces,
242  mergedPoints
243  );
244 
245  // Write
246  if (Pstream::master())
247  {
248  writer.write(outputDir, name, mergedPoints, mergedFaces);
249  }
250  }
251  else
252  {
253  writer.write
254  (
255  outputDir,
256  name,
257  setPatch.localPoints(),
258  setPatch.localFaces()
259  );
260  }
261 }
262 
263 
265 {
266  return
267  mesh.time().globalPath()
268  /functionObjects::writeFile::outputPrefix
269  /(
270  (mesh.name() != polyMesh::defaultRegion)
271  ? mesh.name()
272  : word::null
273  )
274  /"checkMesh"
275  /mesh.pointsInstance();
276 }
277 
278 
280 (
281  const surfaceWriter& writer,
282  const faceSet& set
283 )
284 {
285  const polyMesh& mesh = refCast<const polyMesh>(set.db());
286 
287  const indirectPrimitivePatch setPatch
288  (
289  IndirectList<face>(mesh.faces(), set.sortedToc()),
290  mesh.points()
291  );
292 
293  mergeAndWrite(mesh, writer, set.name(), setPatch, checkMeshOutputDir(mesh));
294 }
295 
296 
298 (
299  const surfaceWriter& writer,
300  const cellSet& set
301 )
302 {
303  const polyMesh& mesh = refCast<const polyMesh>(set.db());
304  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
305 
306 
307  // Determine faces on outside of cellSet
308  PackedBoolList isInSet(mesh.nCells());
309  forAllConstIter(cellSet, set, iter)
310  {
311  isInSet[iter.key()] = true;
312  }
313 
314 
315  boolList bndInSet(mesh.nFaces()-mesh.nInternalFaces());
316  forAll(pbm, patchi)
317  {
318  const polyPatch& pp = pbm[patchi];
319  const labelList& fc = pp.faceCells();
320  forAll(fc, i)
321  {
322  bndInSet[pp.start()+i-mesh.nInternalFaces()] = isInSet[fc[i]];
323  }
324  }
325  syncTools::swapBoundaryFaceList(mesh, bndInSet);
326 
327 
328  DynamicList<label> outsideFaces(3*set.size());
329  for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
330  {
331  bool ownVal = isInSet[mesh.faceOwner()[facei]];
332  bool neiVal = isInSet[mesh.faceNeighbour()[facei]];
333 
334  if (ownVal != neiVal)
335  {
336  outsideFaces.append(facei);
337  }
338  }
339 
340 
341  forAll(pbm, patchi)
342  {
343  const polyPatch& pp = pbm[patchi];
344  const labelList& fc = pp.faceCells();
345  if (pp.coupled())
346  {
347  forAll(fc, i)
348  {
349  label facei = pp.start()+i;
350 
351  bool neiVal = bndInSet[facei-mesh.nInternalFaces()];
352  if (isInSet[fc[i]] && !neiVal)
353  {
354  outsideFaces.append(facei);
355  }
356  }
357  }
358  else
359  {
360  forAll(fc, i)
361  {
362  if (isInSet[fc[i]])
363  {
364  outsideFaces.append(pp.start()+i);
365  }
366  }
367  }
368  }
369 
370 
371  const indirectPrimitivePatch setPatch
372  (
373  IndirectList<face>(mesh.faces(), outsideFaces),
374  mesh.points()
375  );
376 
377  const fileName outputDir(checkMeshOutputDir(mesh));
378  outputDir.clean();
379 
380  mergeAndWrite(mesh, writer, set.name(), setPatch, outputDir);
381 }
382 
383 
385 (
386  const setWriter& writer,
387  const pointSet& set
388 )
389 {
390  const polyMesh& mesh = refCast<const polyMesh>(set.db());
391 
392  pointField mergedPts;
393  labelList mergedIDs;
394 
395  if (Pstream::parRun())
396  {
397  // Note: we explicitly do not merge the points
398  // (mesh.globalData().mergePoints etc) since this might
399  // hide any synchronisation problem
400 
401  globalIndex globalNumbering(mesh.nPoints());
402 
403  mergedPts.setSize(returnReduce(set.size(), sumOp<label>()));
404  mergedIDs.setSize(mergedPts.size());
405 
406  labelList setPointIDs(set.sortedToc());
407 
408  // Get renumbered local data
409  pointField myPoints(mesh.points(), setPointIDs);
410  labelList myIDs(setPointIDs.size());
411  forAll(setPointIDs, i)
412  {
413  myIDs[i] = globalNumbering.toGlobal(setPointIDs[i]);
414  }
415 
416  if (Pstream::master())
417  {
418  // Insert master data first
419  label pOffset = 0;
420  SubList<point>(mergedPts, myPoints.size(), pOffset) = myPoints;
421  SubList<label>(mergedIDs, myIDs.size(), pOffset) = myIDs;
422  pOffset += myPoints.size();
423 
424  // Receive slave ones
425  for (int slave=1; slave<Pstream::nProcs(); slave++)
426  {
427  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
428 
429  pointField slavePts(fromSlave);
430  labelList slaveIDs(fromSlave);
431 
432  SubList<point>(mergedPts, slavePts.size(), pOffset) = slavePts;
433  SubList<label>(mergedIDs, slaveIDs.size(), pOffset) = slaveIDs;
434  pOffset += slaveIDs.size();
435  }
436  }
437  else
438  {
439  // Construct processor stream with estimate of size. Could
440  // be improved.
441  OPstream toMaster
442  (
443  Pstream::commsTypes::scheduled,
444  Pstream::masterNo(),
445  myPoints.byteSize() + myIDs.byteSize()
446  );
447  toMaster << myPoints << myIDs;
448  }
449  }
450  else
451  {
452  mergedIDs = set.sortedToc();
453  mergedPts = pointField(mesh.points(), mergedIDs);
454  }
455 
456  // Write with scalar pointID
457  if (Pstream::master())
458  {
459  writer.write
460  (
461  checkMeshOutputDir(mesh),
462  set.name(),
463  coordSet(false, word::null, mergedPts),
464  "pointID",
465  scalarField(scalarList(mergedIDs))
466  );
467  }
468 }
469 
470 
471 // ************************************************************************* //
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
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
List< Key > sortedToc() const
Return the table of contents as a sorted list.
Definition: HashTable.C:242
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
const objectRegistry & db() const
Return the local objectRegistry.
Definition: IOobject.C:312
const word & name() const
Return name.
Definition: IOobject.H:310
Input inter-processor communications stream.
Definition: IPstream.H:54
A List with indirect addressing.
Definition: IndirectList.H:105
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output inter-processor communications stream.
Definition: OPstream.H:54
A bit-packed bool list.
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.
const Map< label > & meshPointMap() const
Mesh point map. Given the global point index find its.
const labelList & meshPoints() const
Return labelList of mesh points in patch. They are constructed.
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
A List obtained as a section of another List.
Definition: SubList.H:56
fileName globalPath() const
Return the global path.
Definition: TimePaths.H:132
std::streamsize byteSize() const
Return the binary size in number of characters of the UList.
Definition: UList.C:100
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
A collection of cell labels.
Definition: cellSet.H:51
Holds list of sampling positions.
Definition: coordSet.H:51
A list of face labels.
Definition: faceSet.H:51
A class for handling file names.
Definition: fileName.H:82
bool clean()
Cleanup file name.
Definition: fileName.C:93
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:101
A cellMatcher for hex cells.
Definition: hexMatcher.H:54
const Time & time() const
Return time.
A set of point labels.
Definition: pointSet.H:51
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const pointZoneList & pointZones() const
Return point zones.
Definition: polyMesh.H:440
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:452
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1326
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1339
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:965
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:446
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:404
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1345
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1313
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:290
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:280
const labelUList & faceCells() const
Return face-cell addressing.
Definition: polyPatch.C:313
label nEdges() const
label nCells() const
label nPoints() const
label nInternal1Edges() const
Internal edges using 0 or 1 boundary point.
label nInternalFaces() const
label nInternal0Edges() const
Internal edges (i.e. not on boundary face) using.
label nFaces() const
label nInternalEdges() const
Internal edges using 0,1 or 2 boundary points.
label nInternalPoints() const
Points not on boundary.
const cellList & cells() const
A cellMatcher for prism cells.
Definition: prismMatcher.H:54
virtual bool isA(const primitiveMesh &mesh, const label celli)
Exact match. Uses faceSizeMatch.
Definition: prismMatcher.C:343
A cellMatcher for pyr cells.
Definition: pyrMatcher.H:54
virtual bool isA(const primitiveMesh &mesh, const label celli)
Exact match. Uses faceSizeMatch.
Definition: pyrMatcher.C:267
Base class for writing coordinate sets with data.
Definition: setWriter.H:64
virtual void write(const fileName &outputDir, const fileName &setName, const coordSet &set, const wordList &valueSetNames #define TypeValueSetsConstArg(Type, nullArg)) const =0
Write a coordSet and associated data.
Base class for surface writers.
Definition: surfaceWriter.H:55
virtual void write(const fileName &outputDir, const fileName &surfaceName, const pointField &points, const faceList &faces, const wordList &fieldNames, const bool writePointValues #define FieldTypeValuesConstArg(Type, nullArg)) const =0
Write fields for a single surface to file.
A cellMatcher for tet cells.
Definition: tetMatcher.H:54
virtual bool isA(const primitiveMesh &mesh, const label celli)
Exact match. Uses faceSizeMatch.
Definition: tetMatcher.C:218
A cellMatcher for tetWedge cells.
virtual bool isA(const primitiveMesh &mesh, const label celli)
Exact match. Uses faceSizeMatch.
A cellMatcher for wedge cells.
Definition: wedgeMatcher.H:54
virtual bool isA(const primitiveMesh &mesh, const label celli)
Exact match. Uses faceSizeMatch.
Definition: wedgeMatcher.C:370
A class for handling words, derived from string.
Definition: word.H:62
volScalarField scalarField(fieldObject, mesh)
label patchi
Tools for checking the mesh.
#define WarningInFunction
Report a warning using Foam::Warning.
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.
fileName checkMeshOutputDir(const polyMesh &mesh)
Output directory for sets and surfaces.
void printMeshStats(const polyMesh &mesh, const bool allTopology)
Print mesh statistics.
Definition: mergeAndWrite.C:50
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:164
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:257
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
IOstream & hex(IOstream &io)
Definition: IOstream.H:561
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
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)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
static const char nl
Definition: Ostream.H:266