conformalVoronoiMeshIO.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) 2012-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2022 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 "conformalVoronoiMesh.H"
30 #include "IOstreams.H"
31 #include "OFstream.H"
32 #include "pointMesh.H"
33 #include "pointFields.H"
34 #include "ListOps.H"
35 #include "polyMeshFilter.H"
36 #include "polyTopoChange.H"
37 #include "PrintTable.H"
38 #include "indexedVertexOps.H"
39 #include "DelaunayMeshTools.H"
40 #include "syncTools.H"
41 #include "faceSet.H"
42 #include "OBJstream.H"
43 
44 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
45 
47 (
48  const string& description
49 ) const
50 {
51  timeCheck(time(), description, foamyHexMeshControls().timeChecks());
52 }
53 
54 
56 (
57  const Time& runTime,
58  const string& description,
59  const bool check
60 )
61 {
62  if (check)
63  {
64  Info<< nl << "--- [ cpuTime "
65  << runTime.elapsedCpuTime() << " s, "
66  << "delta " << runTime.cpuTimeIncrement()<< " s";
67 
68  if (description != word::null)
69  {
70  Info<< ", " << description << " ";
71  }
72  else
73  {
74  Info<< " ";
75  }
76 
77  Info<< "] --- " << endl;
78 
79  memInfo m;
80 
81  if (m.valid())
82  {
83  PrintTable<word, label> memoryTable
84  (
85  "Memory Usage (kB): "
86  + description
87  );
88 
89  memoryTable.add("mSize", m.size());
90  memoryTable.add("mPeak", m.peak());
91  memoryTable.add("mRss", m.rss());
92 
93  Info<< incrIndent;
94  memoryTable.print(Info, true, true);
95  Info<< decrIndent;
96  }
97  }
98 }
99 
100 
101 void Foam::conformalVoronoiMesh::writeMesh(const fileName& instance)
102 {
104 
105  // Per cell the Delaunay vertex
106  labelList cellToDelaunayVertex;
107  // Per patch, per face the Delaunay vertex
108  labelListList patchToDelaunayVertex;
109 
110  labelList dualPatchStarts;
111 
112  {
114  labelList boundaryPts;
115  faceList faces;
116  labelList owner;
117  labelList neighbour;
119  PtrList<dictionary> patchDicts;
120  pointField cellCentres;
121  bitSet boundaryFacesToRemove;
122 
123  calcDualMesh
124  (
125  points,
126  boundaryPts,
127  faces,
128  owner,
129  neighbour,
130  patchNames,
131  patchDicts,
132  cellCentres,
133  cellToDelaunayVertex,
134  patchToDelaunayVertex,
135  boundaryFacesToRemove
136  );
137 
138  Info<< nl << "Writing polyMesh to " << instance << endl;
139 
140  writeMesh
141  (
143  instance,
144  points,
145  boundaryPts,
146  faces,
147  owner,
148  neighbour,
149  patchNames,
150  patchDicts,
151  cellCentres,
152  boundaryFacesToRemove
153  );
154 
155  dualPatchStarts.setSize(patchDicts.size());
156 
157  forAll(dualPatchStarts, patchi)
158  {
159  dualPatchStarts[patchi] =
160  patchDicts[patchi].get<label>("startFace");
161  }
162  }
163 
164  if (foamyHexMeshControls().writeCellShapeControlMesh())
165  {
166  cellShapeControls().shapeControlMesh().write();
167  }
168 
169  if (foamyHexMeshControls().writeBackgroundMeshDecomposition())
170  {
171  Info<< nl << "Writing " << "backgroundMeshDecomposition" << endl;
172 
173  // Have to explicitly update the mesh instance.
174  const_cast<fvMesh&>(decomposition_().mesh()).setInstance
175  (
176  time().timeName()
177  );
178 
179  decomposition_().mesh().write();
180  }
181 
182  if (foamyHexMeshControls().writeTetDualMesh())
183  {
184  label celli = 0;
185  for
186  (
187  Finite_cells_iterator cit = finite_cells_begin();
188  cit != finite_cells_end();
189  ++cit
190  )
191  {
192  if
193  (
194  !cit->hasFarPoint()
195  && !is_infinite(cit)
196  )
197  {
198  cit->cellIndex() = celli++;
199  }
200  }
201 
202  Info<< nl << "Writing " << "tetDualMesh" << endl;
203 
204  labelPairLookup vertexMap;
205  labelList cellMap;
206  autoPtr<polyMesh> tetMesh =
207  createMesh("tetDualMesh", vertexMap, cellMap);
208 
209  tetMesh().write();
210 
211 // // Determine map from Delaunay vertex to Dual mesh
212 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
213 //
214 // // From all Delaunay vertices to cell (positive index)
215 // // or patch face (negative index)
216 // labelList vertexToDualAddressing(number_of_vertices(), Zero);
217 //
218 // forAll(cellToDelaunayVertex, celli)
219 // {
220 // label vertI = cellToDelaunayVertex[celli];
221 //
222 // if (vertexToDualAddressing[vertI] != 0)
223 // {
224 // FatalErrorInFunction
225 // << "Delaunay vertex " << vertI
226 // << " from cell " << celli
227 // << " is already mapped to "
228 // << vertexToDualAddressing[vertI]
229 // << exit(FatalError);
230 // }
231 // vertexToDualAddressing[vertI] = celli+1;
232 // }
233 //
234 // forAll(patchToDelaunayVertex, patchi)
235 // {
236 // const labelList& patchVertices = patchToDelaunayVertex[patchi];
237 //
238 // forAll(patchVertices, i)
239 // {
240 // label vertI = patchVertices[i];
241 //
242 // if (vertexToDualAddressing[vertI] > 0)
243 // {
244 // FatalErrorInFunction
245 // << "Delaunay vertex " << vertI
246 // << " from patch " << patchi
247 // << " local index " << i
248 // << " is already mapped to cell "
249 // << vertexToDualAddressing[vertI]-1
250 // << exit(FatalError);
251 // }
252 //
253 // // Vertex might be used by multiple faces. Which one to
254 // // use? For now last one wins.
255 // label dualFacei = dualPatchStarts[patchi]+i;
256 // vertexToDualAddressing[vertI] = -dualFacei-1;
257 // }
258 // }
259 //
260 //
261 // // Calculate tet mesh addressing
262 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
263 //
264 // pointField points;
265 // labelList boundaryPts(number_of_finite_cells(), -1);
266 // // From tet point back to Delaunay vertex index
267 // labelList pointToDelaunayVertex;
268 // faceList faces;
269 // labelList owner;
270 // labelList neighbour;
271 // wordList patchTypes;
272 // wordList patchNames;
273 // PtrList<dictionary> patchDicts;
274 // pointField cellCentres;
275 //
276 // calcTetMesh
277 // (
278 // points,
279 // pointToDelaunayVertex,
280 // faces,
281 // owner,
282 // neighbour,
283 // patchTypes,
284 // patchNames,
285 // patchDicts
286 // );
287 //
288 //
289 //
290 // // Calculate map from tet points to dual mesh cells/patch faces
291 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
292 //
293 // labelIOList pointDualAddressing
294 // (
295 // IOobject
296 // (
297 // "pointDualAddressing",
298 // instance,
299 // "tetDualMesh"/polyMesh::meshSubDir,
300 // runTime_,
301 // IOobject::NO_READ,
302 // IOobject::AUTO_WRITE,
303 // false
304 // ),
305 // labelUIndList
306 // (
307 // vertexToDualAddressing,
308 // pointToDelaunayVertex
309 // )()
310 // );
311 //
312 // label pointi = pointDualAddressing.find(-1);
313 // if (pointi != -1)
314 // {
315 // WarningInFunction
316 // << "Delaunay vertex " << pointi
317 // << " does not have a corresponding dual cell." << endl;
318 // }
319 //
320 // Info<< "Writing map from tetDualMesh points to Voronoi mesh to "
321 // << pointDualAddressing.objectPath() << endl;
322 // pointDualAddressing.write();
323 //
324 //
325 //
326 // // Write tet points corresponding to the Voronoi cell/face centre
327 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
328 // {
329 // // Read Voronoi mesh
330 // fvMesh mesh
331 // (
332 // IOobject
333 // (
334 // polyMesh::defaultRegion,
335 // instance,
336 // runTime_,
337 // IOobject::MUST_READ
338 // )
339 // );
340 // pointIOField dualPoints
341 // (
342 // IOobject
343 // (
344 // "dualPoints",
345 // instance,
346 // "tetDualMesh"/polyMesh::meshSubDir,
347 // runTime_,
348 // IOobject::NO_READ,
349 // IOobject::AUTO_WRITE,
350 // false
351 // ),
352 // points
353 // );
354 //
355 // forAll(pointDualAddressing, pointi)
356 // {
357 // label index = pointDualAddressing[pointi];
358 //
359 // if (index > 0)
360 // {
361 // label celli = index-1;
362 // dualPoints[pointi] = mesh.cellCentres()[celli];
363 // }
364 // else if (index < 0)
365 // {
366 // label facei = -index-1;
367 // if (facei >= mesh.nInternalFaces())
368 // {
369 // dualPoints[pointi] = mesh.faceCentres()[facei];
370 // }
371 // }
372 // }
373 //
374 // Info<< "Writing tetDualMesh points mapped onto Voronoi mesh to "
375 // << dualPoints.objectPath() << endl
376 // << "Replace the polyMesh/points with these." << endl;
377 // dualPoints.write();
378 // }
379 //
380 //
381 // Info<< nl << "Writing tetDualMesh to " << instance << endl;
382 //
383 // bitSet boundaryFacesToRemove;
384 // writeMesh
385 // (
386 // "tetDualMesh",
387 // instance,
388 // points,
389 // boundaryPts,
390 // faces,
391 // owner,
392 // neighbour,
393 // patchTypes,
394 // patchNames,
395 // patchDicts,
396 // cellCentres,
397 // boundaryFacesToRemove
398 // );
399  }
400 }
401 
402 
403 Foam::autoPtr<Foam::fvMesh> Foam::conformalVoronoiMesh::createDummyMesh
404 (
405  const IOobject& io,
406  const wordList& patchNames,
407  const PtrList<dictionary>& patchDicts
408 ) const
409 {
411  fvMesh& mesh = meshPtr();
412 
413  List<polyPatch*> patches(patchDicts.size());
414 
415  forAll(patches, patchi)
416  {
417  if
418  (
419  patchDicts.set(patchi)
420  && (
421  patchDicts[patchi].get<word>("type")
422  == processorPolyPatch::typeName
423  )
424  )
425  {
426  patches[patchi] = new processorPolyPatch
427  (
428  0, //patchSizes[p],
429  0, //patchStarts[p],
430  patchi,
431  mesh.boundaryMesh(),
432  patchDicts[patchi].get<label>("myProcNo"),
433  patchDicts[patchi].get<label>("neighbProcNo"),
435  );
436  }
437  else
438  {
439  patches[patchi] = polyPatch::New
440  (
441  patchDicts[patchi].get<word>("type"),
442  patchNames[patchi],
443  0, //patchSizes[p],
444  0, //patchStarts[p],
445  patchi,
447  ).ptr();
448  }
449  }
450 
452 
453  return meshPtr;
454 }
455 
456 
457 void Foam::conformalVoronoiMesh::checkProcessorPatchesMatch
458 (
459  const PtrList<dictionary>& patchDicts
460 ) const
461 {
462  // Check patch sizes
463  labelListList procPatchSizes
464  (
465  Pstream::nProcs(),
467  );
468 
469  forAll(patchDicts, patchi)
470  {
471  if
472  (
473  patchDicts.set(patchi)
474  && (
475  patchDicts[patchi].get<word>("type")
476  == processorPolyPatch::typeName
477  )
478  )
479  {
480  const label procNeighb =
481  patchDicts[patchi].get<label>("neighbProcNo");
482 
483  procPatchSizes[Pstream::myProcNo()][procNeighb]
484  = patchDicts[patchi].get<label>("nFaces");
485  }
486  }
487 
488  Pstream::gatherList(procPatchSizes);
489 
490  if (Pstream::master())
491  {
492  bool allMatch = true;
493 
494  forAll(procPatchSizes, proci)
495  {
496  const labelList& patchSizes = procPatchSizes[proci];
497 
498  forAll(patchSizes, patchi)
499  {
500  if (patchSizes[patchi] != procPatchSizes[patchi][proci])
501  {
502  allMatch = false;
503 
504  Info<< indent << "Patches " << proci << " and " << patchi
505  << " have different sizes: " << patchSizes[patchi]
506  << " and " << procPatchSizes[patchi][proci] << endl;
507  }
508  }
509  }
510 
511  if (allMatch)
512  {
513  Info<< indent << "All processor patches have matching numbers of "
514  << "faces" << endl;
515  }
516  }
517 }
518 
519 
520 void Foam::conformalVoronoiMesh::reorderPoints
521 (
523  labelList& boundaryPts,
524  faceList& faces,
525  const label nInternalFaces
526 ) const
527 {
528  Info<< incrIndent << indent << "Reordering points into internal/external"
529  << endl;
530 
531  labelList oldToNew(points.size(), Zero);
532 
533  // Find points that are internal
534  for (label fI = nInternalFaces; fI < faces.size(); ++fI)
535  {
536  const face& f = faces[fI];
537 
538  forAll(f, fpI)
539  {
540  oldToNew[f[fpI]] = 1;
541  }
542  }
543 
544  const label nInternalPoints = points.size() - sum(oldToNew);
545 
546  label countInternal = 0;
547  label countExternal = nInternalPoints;
548 
549  forAll(points, pI)
550  {
551  if (oldToNew[pI] == 0)
552  {
553  oldToNew[pI] = countInternal++;
554  }
555  else
556  {
557  oldToNew[pI] = countExternal++;
558  }
559  }
560 
561  Info<< indent
562  << "Number of internal points: " << countInternal << nl
563  << indent << "Number of external points: " << countExternal
564  << decrIndent << endl;
565 
566  inplaceReorder(oldToNew, points);
567  inplaceReorder(oldToNew, boundaryPts);
568 
569  forAll(faces, fI)
570  {
571  face& f = faces[fI];
572 
573  forAll(f, fpI)
574  {
575  f[fpI] = oldToNew[f[fpI]];
576  }
577  }
578 }
579 
580 
581 void Foam::conformalVoronoiMesh::reorderProcessorPatches
582 (
583  const word& meshName,
584  const fileName& instance,
585  const pointField& points,
586  faceList& faces,
587  const wordList& patchNames,
588  const PtrList<dictionary>& patchDicts
589 ) const
590 {
591  Info<< incrIndent << indent << "Reordering processor patches" << endl;
592 
593  Info<< incrIndent;
594  checkProcessorPatchesMatch(patchDicts);
595 
596  // Create dummy mesh with correct proc boundaries to do sorting
597  autoPtr<fvMesh> sortMeshPtr
598  (
599  createDummyMesh
600  (
601  IOobject
602  (
603  meshName,
604  instance,
605  runTime_,
608  false
609  ),
610  patchNames,
611  patchDicts
612  )
613  );
614  const fvMesh& sortMesh = sortMeshPtr();
615 
616  // Rotation on new faces.
617  labelList rotation(faces.size(), Zero);
618  labelList faceMap(faces.size(), label(-1));
619 
620  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
621 
622  // Send ordering
623  forAll(sortMesh.boundaryMesh(), patchi)
624  {
625  const polyPatch& pp = sortMesh.boundaryMesh()[patchi];
626 
627  if (isA<processorPolyPatch>(pp))
628  {
629  refCast<const processorPolyPatch>(pp).initOrder
630  (
631  pBufs,
633  (
634  SubList<face>
635  (
636  faces,
637  patchDicts[patchi].get<label>("nFaces"),
638  patchDicts[patchi].get<label>("startFace")
639  ),
640  points
641  )
642  );
643  }
644  }
645 
646  pBufs.finishedSends();
647 
648  Info<< incrIndent << indent << "Face ordering initialised..." << endl;
649 
650  // Receive and calculate ordering
651  bool anyChanged = false;
652 
653  forAll(sortMesh.boundaryMesh(), patchi)
654  {
655  const polyPatch& pp = sortMesh.boundaryMesh()[patchi];
656 
657  if (isA<processorPolyPatch>(pp))
658  {
659  const label nPatchFaces =
660  patchDicts[patchi].get<label>("nFaces");
661 
662  const label patchStartFace =
663  patchDicts[patchi].get<label>("startFace");
664 
665  labelList patchFaceMap(nPatchFaces, label(-1));
666  labelList patchFaceRotation(nPatchFaces, Zero);
667 
668  bool changed = refCast<const processorPolyPatch>(pp).order
669  (
670  pBufs,
672  (
673  SubList<face>
674  (
675  faces,
676  nPatchFaces,
677  patchStartFace
678  ),
679  points
680  ),
681  patchFaceMap,
682  patchFaceRotation
683  );
684 
685  if (changed)
686  {
687  // Merge patch face reordering into mesh face reordering table
688  forAll(patchFaceRotation, patchFacei)
689  {
690  rotation[patchFacei + patchStartFace]
691  = patchFaceRotation[patchFacei];
692  }
693 
694  forAll(patchFaceMap, patchFacei)
695  {
696  if (patchFaceMap[patchFacei] != patchFacei)
697  {
698  faceMap[patchFacei + patchStartFace]
699  = patchFaceMap[patchFacei] + patchStartFace;
700  }
701  }
702 
703  anyChanged = true;
704  }
705  }
706  }
707 
708  Info<< incrIndent << indent << "Faces matched." << endl;
709 
710  if (returnReduceOr(anyChanged))
711  {
712  label nReorderedFaces = 0;
713 
714  forAll(faceMap, facei)
715  {
716  if (faceMap[facei] != -1)
717  {
718  nReorderedFaces++;
719  }
720  }
721 
722  if (nReorderedFaces > 0)
723  {
724  inplaceReorder(faceMap, faces);
725  }
726 
727  // Rotate faces (rotation is already in new face indices).
728  label nRotated = 0;
729 
730  forAll(rotation, facei)
731  {
732  if (rotation[facei] != 0)
733  {
734  faces[facei] = rotateList(faces[facei], rotation[facei]);
735  nRotated++;
736  }
737  }
738 
739  Info<< indent << returnReduce(nReorderedFaces, sumOp<label>())
740  << " faces have been reordered" << nl
741  << indent << returnReduce(nRotated, sumOp<label>())
742  << " faces have been rotated"
743  << decrIndent << decrIndent
744  << decrIndent << decrIndent << endl;
745  }
746 }
747 
748 
750 (
751  const word& meshName,
752  const fileName& instance,
754  labelList& boundaryPts,
755  faceList& faces,
756  labelList& owner,
757  labelList& neighbour,
758  const wordList& patchNames,
759  const PtrList<dictionary>& patchDicts,
760  const pointField& cellCentres,
761  bitSet& boundaryFacesToRemove
762 ) const
763 {
764  if (foamyHexMeshControls().objOutput())
765  {
767  (
768  time().path()/word(meshName + ".obj"),
769  points,
770  faces
771  );
772  }
773 
774  const label nInternalFaces = patchDicts[0].get<label>("startFace");
775 
776  reorderPoints(points, boundaryPts, faces, nInternalFaces);
777 
778  if (Pstream::parRun())
779  {
780  reorderProcessorPatches
781  (
782  meshName,
783  instance,
784  points,
785  faces,
786  patchNames,
787  patchDicts
788  );
789  }
790 
791  Info<< incrIndent;
792  Info<< indent << "Constructing mesh" << endl;
793 
794  timeCheck("Before fvMesh construction");
795 
796  fvMesh mesh
797  (
798  IOobject
799  (
800  meshName,
801  instance,
802  runTime_,
805  ),
806  std::move(points),
807  std::move(faces),
808  std::move(owner),
809  std::move(neighbour)
810  );
811 
812  Info<< indent << "Adding patches to mesh" << endl;
813 
814  List<polyPatch*> patches(patchNames.size());
815 
816  label nValidPatches = 0;
817 
818  forAll(patches, p)
819  {
820  label totalPatchSize = patchDicts[p].get<label>("nFaces");
821 
822  if
823  (
824  patchDicts.set(p)
825  && (
826  patchDicts[p].get<word>("type")
827  == processorPolyPatch::typeName
828  )
829  )
830  {
831  const_cast<dictionary&>(patchDicts[p]).set
832  (
833  "transform",
834  "coincidentFullMatch"
835  );
836 
837  // Do not create empty processor patches
838  if (totalPatchSize > 0)
839  {
840  patches[nValidPatches] = new processorPolyPatch
841  (
842  patchNames[p],
843  patchDicts[p],
844  nValidPatches,
845  mesh.boundaryMesh(),
846  processorPolyPatch::typeName
847  );
848 
849  nValidPatches++;
850  }
851  }
852  else
853  {
854  // Check that the patch is not empty on every processor
855  reduce(totalPatchSize, sumOp<label>());
856 
857  if (totalPatchSize > 0)
858  {
859  patches[nValidPatches] = polyPatch::New
860  (
861  patchNames[p],
862  patchDicts[p],
863  nValidPatches,
865  ).ptr();
866 
867  nValidPatches++;
868  }
869  }
870  }
871 
872  patches.setSize(nValidPatches);
873 
875 
876 
877  // Add zones to the mesh
878  addZones(mesh, cellCentres);
879 
880 
881  Info<< indent << "Add pointZones" << endl;
882  {
883  label sz = mesh.pointZones().size();
884 
885  DynamicList<label> bPts(boundaryPts.size());
886 
887  forAll(dualMeshPointTypeNames_, typeI)
888  {
889  const word& znName =
890  dualMeshPointTypeNames_[dualMeshPointType(typeI)];
891 
892  forAll(boundaryPts, ptI)
893  {
894  const label& bPtType = boundaryPts[ptI];
895 
896  if (bPtType == typeI)
897  {
898  bPts.append(ptI);
899  }
900  }
901 
902 // syncTools::syncPointList(mesh, bPts, maxEqOp<label>(), -1);
903 
904  Info<< incrIndent << indent
905  << "Adding " << bPts.size()
906  << " points of type " << znName
907  << decrIndent << endl;
908 
910  (
911  new pointZone
912  (
913  znName,
914  bPts,
915  sz + typeI,
916  mesh.pointZones()
917  )
918  );
919 
920  bPts.clear();
921  }
922  }
923 
924 
925 
926  // Add indirectPatchFaces to a face zone
927  Info<< indent << "Adding indirect patch faces set" << endl;
928 
930  (
931  mesh,
932  boundaryFacesToRemove,
933  orEqOp<unsigned int>()
934  );
935 
936  labelList addr(boundaryFacesToRemove.toc());
937 
938  faceSet indirectPatchFaces
939  (
940  mesh,
941  "indirectPatchFaces",
942  addr,
944  );
945 
946  indirectPatchFaces.sync(mesh);
947 
948 
949  Info<< decrIndent;
950 
951  timeCheck("Before fvMesh filtering");
952 
953  autoPtr<polyMeshFilter> meshFilter;
954 
955  label nInitialBadFaces = 0;
956 
957  if (foamyHexMeshControls().filterEdges())
958  {
959  Info<< nl << "Filtering edges on polyMesh" << nl << endl;
960 
961  meshFilter.reset(new polyMeshFilter(mesh, boundaryPts));
962 
963  // Filter small edges only. This reduces the number of faces so that
964  // the face filtering is sped up.
965  nInitialBadFaces = meshFilter().filterEdges(0);
966  {
967  const autoPtr<fvMesh>& newMesh = meshFilter().filteredMesh();
968 
969  polyTopoChange meshMod(newMesh());
970 
971  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
972 
973  polyMeshFilter::copySets(newMesh(), mesh);
974  }
975  }
976 
977  if (foamyHexMeshControls().filterFaces())
978  {
979  labelIOList boundaryPtsIO
980  (
981  IOobject
982  (
983  "pointPriority",
984  instance,
985  time(),
988  ),
990  );
991 
992  forAll(mesh.points(), ptI)
993  {
994  boundaryPtsIO[ptI] = mesh.pointZones().whichZone(ptI);
995  }
996 
997 
998  Info<< nl << "Filtering faces on polyMesh" << nl << endl;
999 
1000  meshFilter.reset(new polyMeshFilter(mesh, boundaryPtsIO));
1001 
1002  meshFilter().filter(nInitialBadFaces);
1003  {
1004  const autoPtr<fvMesh>& newMesh = meshFilter().filteredMesh();
1005 
1006  polyTopoChange meshMod(newMesh());
1007 
1008  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
1009 
1010  polyMeshFilter::copySets(newMesh(), mesh);
1011  }
1012  }
1013 
1014  timeCheck("After fvMesh filtering");
1015 
1016  mesh.setInstance(instance);
1017 
1018  if (!mesh.write())
1019  {
1021  << "Failed writing polyMesh."
1022  << exit(FatalError);
1023  }
1024  else
1025  {
1026  Info<< nl << "Written filtered mesh to "
1027  << mesh.polyMesh::instance() << nl
1028  << endl;
1029  }
1030 
1031  {
1032  pointScalarField boundaryPtsScalarField
1033  (
1034  IOobject
1035  (
1036  "boundaryPoints_collapsed",
1037  instance,
1038  time(),
1041  ),
1043  dimensionedScalar("min", dimless, scalar(labelMin))
1044  );
1045 
1046  labelIOList boundaryPtsIO
1047  (
1048  IOobject
1049  (
1050  "pointPriority",
1051  instance,
1052  time(),
1055  ),
1057  );
1058 
1059  forAll(mesh.points(), ptI)
1060  {
1061  boundaryPtsScalarField[ptI] = mesh.pointZones().whichZone(ptI);
1062  boundaryPtsIO[ptI] = mesh.pointZones().whichZone(ptI);
1063  }
1064 
1065  boundaryPtsScalarField.write();
1066  boundaryPtsIO.write();
1067  }
1068 
1069 // writeCellSizes(mesh);
1070 
1071 // writeCellAlignments(mesh);
1072 
1073 // writeCellCentres(mesh);
1074 
1075  findRemainingProtrusionSet(mesh);
1076 }
1077 
1078 
1080 (
1081  const fvMesh& mesh
1082 ) const
1083 {
1084  {
1085  timeCheck("Start writeCellSizes");
1086 
1087  Info<< nl << "Create targetCellSize volScalarField" << endl;
1088 
1089  volScalarField targetCellSize
1090  (
1091  IOobject
1092  (
1093  "targetCellSize",
1094  mesh.polyMesh::instance(),
1095  mesh,
1098  ),
1099  mesh,
1101  zeroGradientFvPatchScalarField::typeName
1102  );
1103 
1104  scalarField& cellSize = targetCellSize.primitiveFieldRef();
1105 
1106  const vectorField& C = mesh.cellCentres();
1107 
1108  forAll(cellSize, i)
1109  {
1110  cellSize[i] = cellShapeControls().cellSize(C[i]);
1111  }
1112 
1113  // Info<< nl << "Create targetCellVolume volScalarField" << endl;
1114 
1115  // volScalarField targetCellVolume
1116  // (
1117  // IOobject
1118  // (
1119  // "targetCellVolume",
1120  // mesh.polyMesh::instance(),
1121  // mesh,
1122  // IOobject::NO_READ,
1123  // IOobject::AUTO_WRITE
1124  // ),
1125  // mesh,
1126  // dimensionedScalar(dimLength, Zero),
1127  // zeroGradientFvPatchScalarField::typeName
1128  // );
1129 
1130  // targetCellVolume.primitiveFieldRef() = pow3(cellSize);
1131 
1132  // Info<< nl << "Create actualCellVolume volScalarField" << endl;
1133 
1134  // volScalarField actualCellVolume
1135  // (
1136  // IOobject
1137  // (
1138  // "actualCellVolume",
1139  // mesh.polyMesh::instance(),
1140  // mesh,
1141  // IOobject::NO_READ,
1142  // IOobject::AUTO_WRITE
1143  // ),
1144  // mesh,
1145  // dimensionedScalar(dimVolume, Zero),
1146  // zeroGradientFvPatchScalarField::typeName
1147  // );
1148 
1149  // actualCellVolume.primitiveFieldRef() = mesh.cellVolumes();
1150 
1151  // Info<< nl << "Create equivalentCellSize volScalarField" << endl;
1152 
1153  // volScalarField equivalentCellSize
1154  // (
1155  // IOobject
1156  // (
1157  // "equivalentCellSize",
1158  // mesh.polyMesh::instance(),
1159  // mesh,
1160  // IOobject::NO_READ,
1161  // IOobject::AUTO_WRITE
1162  // ),
1163  // mesh,
1164  // dimensionedScalar(dimLength, Zero),
1165  // zeroGradientFvPatchScalarField::typeName
1166  // );
1167 
1168  // equivalentCellSize.primitiveFieldRef() = pow
1169  // (
1170  // actualCellVolume.primitiveField(),
1171  // 1.0/3.0
1172  // );
1173 
1174  targetCellSize.correctBoundaryConditions();
1175  // targetCellVolume.correctBoundaryConditions();
1176  // actualCellVolume.correctBoundaryConditions();
1177  // equivalentCellSize.correctBoundaryConditions();
1178 
1179  targetCellSize.write();
1180  // targetCellVolume.write();
1181  // actualCellVolume.write();
1182  // equivalentCellSize.write();
1183  }
1184 
1185  // {
1186  // polyMesh tetMesh
1187  // (
1188  // IOobject
1189  // (
1190  // "tetDualMesh",
1191  // runTime_.constant(),
1192  // runTime_,
1193  // IOobject::MUST_READ
1194  // )
1195  // );
1196 
1197  // pointMesh ptMesh(tetMesh);
1198 
1199  // pointScalarField ptTargetCellSize
1200  // (
1201  // IOobject
1202  // (
1203  // "ptTargetCellSize",
1204  // runTime_.timeName(),
1205  // tetMesh,
1206  // IOobject::NO_READ,
1207  // IOobject::AUTO_WRITE
1208  // ),
1209  // ptMesh,
1210  // dimensionedScalar(dimLength, Zero),
1211  // pointPatchVectorField::calculatedType()
1212  // );
1213 
1214  // scalarField& cellSize = ptTargetCellSize.primitiveFieldRef();
1215 
1216  // const vectorField& P = tetMesh.points();
1217 
1218  // forAll(cellSize, i)
1219  // {
1220  // cellSize[i] = cellShapeControls().cellSize(P[i]);
1221  // }
1222 
1223  // ptTargetCellSize.write();
1224  // }
1225 }
1226 
1227 
1229 (
1230  const fvMesh& mesh
1231 ) const
1232 {
1233 // Info<< nl << "Create cellAlignments volTensorField" << endl;
1234 //
1235 // volTensorField cellAlignments
1236 // (
1237 // IOobject
1238 // (
1239 // "cellAlignments",
1240 // mesh.polyMesh::instance(),
1241 // mesh,
1242 // IOobject::NO_READ,
1243 // IOobject::AUTO_WRITE
1244 // ),
1245 // mesh,
1246 // tensor::I,
1247 // zeroGradientFvPatchTensorField::typeName
1248 // );
1249 //
1250 // tensorField& cellAlignment = cellAlignments.primitiveFieldRef();
1251 //
1252 // const vectorField& C = mesh.cellCentres();
1253 //
1254 // vectorField xDir(cellAlignment.size());
1255 // vectorField yDir(cellAlignment.size());
1256 // vectorField zDir(cellAlignment.size());
1257 //
1258 // forAll(cellAlignment, i)
1259 // {
1260 // cellAlignment[i] = cellShapeControls().cellAlignment(C[i]);
1261 // xDir[i] = cellAlignment[i] & vector(1, 0, 0);
1262 // yDir[i] = cellAlignment[i] & vector(0, 1, 0);
1263 // zDir[i] = cellAlignment[i] & vector(0, 0, 1);
1264 // }
1265 //
1266 // OFstream xStr("xDir.obj");
1267 // OFstream yStr("yDir.obj");
1268 // OFstream zStr("zDir.obj");
1269 //
1270 // forAll(xDir, i)
1271 // {
1272 // meshTools::writeOBJ(xStr, C[i], C[i] + xDir[i]);
1273 // meshTools::writeOBJ(yStr, C[i], C[i] + yDir[i]);
1274 // meshTools::writeOBJ(zStr, C[i], C[i] + zDir[i]);
1275 // }
1276 //
1277 // cellAlignments.correctBoundaryConditions();
1278 //
1279 // cellAlignments.write();
1280 }
1281 
1282 
1284 (
1285  const fvMesh& mesh
1286 ) const
1287 {
1288  Info<< "Writing components of cellCentre positions to volScalarFields"
1289  << " ccx, ccy, ccz in " << runTime_.timeName() << endl;
1290 
1291  for (direction i=0; i<vector::nComponents; i++)
1292  {
1293  volScalarField cci
1294  (
1295  IOobject
1296  (
1297  "cc" + word(vector::componentNames[i]),
1298  runTime_.timeName(),
1299  mesh,
1302  ),
1303  mesh.C().component(i)
1304  );
1305 
1306  cci.write();
1307  }
1308 }
1309 
1310 
1312 (
1313  const polyMesh& mesh
1314 ) const
1315 {
1316  timeCheck("Start findRemainingProtrusionSet");
1317 
1318  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1319 
1320  labelHashSet protrudingBoundaryPoints;
1321 
1322  forAll(patches, patchi)
1323  {
1324  const polyPatch& patch = patches[patchi];
1325 
1326  forAll(patch.localPoints(), pLPI)
1327  {
1328  label meshPtI = patch.meshPoints()[pLPI];
1329 
1330  const Foam::point& pt = patch.localPoints()[pLPI];
1331 
1332  if
1333  (
1334  geometryToConformTo_.wellOutside
1335  (
1336  pt,
1337  sqr(targetCellSize(pt))
1338  )
1339  )
1340  {
1341  protrudingBoundaryPoints.insert(meshPtI);
1342  }
1343  }
1344  }
1345 
1346  cellSet protrudingCells
1347  (
1348  mesh,
1349  "foamyHexMesh_remainingProtrusions",
1350  mesh.nCells()/1000
1351  );
1352 
1353  for (const label pointi : protrudingBoundaryPoints)
1354  {
1355  const labelList& pCells = mesh.pointCells()[pointi];
1356  protrudingCells.insert(pCells);
1357  }
1358 
1359  const label protrudingCellsSize =
1360  returnReduce(protrudingCells.size(), sumOp<label>());
1361 
1362  if (foamyHexMeshControls().objOutput() && protrudingCellsSize)
1363  {
1364  Info<< nl << "Found " << protrudingCellsSize
1365  << " cells protruding from the surface, writing cellSet "
1366  << protrudingCells.name()
1367  << endl;
1368 
1369  protrudingCells.write();
1370  }
1371 
1372  return std::move(protrudingCells);
1373 }
1374 
1375 
1376 void Foam::conformalVoronoiMesh::writePointPairs
1377 (
1378  const fileName& fName
1379 ) const
1380 {
1381  OBJstream os(fName);
1382 
1383  for
1384  (
1385  Delaunay::Finite_edges_iterator eit = finite_edges_begin();
1386  eit != finite_edges_end();
1387  ++eit
1388  )
1389  {
1390  Cell_handle c = eit->first;
1391  Vertex_handle vA = c->vertex(eit->second);
1392  Vertex_handle vB = c->vertex(eit->third);
1393 
1394  if (ptPairs_.isPointPair(vA, vB))
1395  {
1396  os.writeLine(topoint(vA->point()), topoint(vB->point()));
1397  }
1398  }
1399 }
1400 
1401 
1402 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:584
labelHashSet findRemainingProtrusionSet(const polyMesh &mesh) const
Find the cellSet of the boundary cells which have points that.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:51
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
uint8_t direction
Definition: direction.H:46
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:449
pointFromPoint topoint(const Point &P)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
label nPoints() const noexcept
Number of mesh points.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
ListType rotateList(const ListType &list, const label n)
Rotate a list by n places.
virtual bool write(const bool valid=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1072
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create a new MeshObject.
Definition: MeshObject.C:41
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
List< face > faceList
A List of faces.
Definition: faceListFwd.H:41
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
tmp< GeometricField< cmptType, PatchField, GeoMesh > > component(const direction) const
Return a component of the field.
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:432
static void timeCheck(const Time &runTime, const string &description=string::null, const bool check=true)
Write the elapsedCpuTime and memory usage, with an optional.
void writeCellCentres(const fvMesh &mesh) const
Calculate and write the cell centres.
constexpr label labelMin
Definition: label.H:54
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
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.
void writeMesh(const fileName &instance)
Prepare data and call writeMesh for polyMesh and.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Various functions to operate on Lists.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1066
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
void writeObjMesh(const fileName &fName, const pointField &points, const faceList &faces)
Write an OBJ mesh consisting of points and faces.
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
void writeCellSizes(const fvMesh &mesh) const
Calculate and write a field of the target cell size,.
dynamicFvMesh & mesh
const pointField & points
Foam::autoPtr< Foam::dynamicFvMesh > meshPtr
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:397
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:99
wordList patchNames(nPatches)
static const word null
An empty word.
Definition: word.H:84
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
GeometricField< scalar, pointPatchField, pointMesh > pointScalarField
const vectorField & cellCentres() const
const labelListList & pointCells() const
Ostream & writeLine(const point &p0, const point &p1)
Write line joining two points.
Definition: OBJstream.C:215
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
OBJstream os(runTime.globalPath()/outputName)
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
virtual void print(Ostream &os) const
Print stream description to Ostream.
Definition: IOstream.C:67
volScalarField & C
void addFvPatches(polyPatchList &plist, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition: fvMesh.C:625
static void check(const int retVal, const char *what)
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:467
labelList f(nPoints)
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:183
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTimePosix.C:80
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:276
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition: polyMesh.H:638
List< word > wordList
A List of words.
Definition: fileName.H:58
void append(autoPtr< T > &ptr)
Move append an element to the end of the list.
Definition: PtrList.H:304
void setInstance(const fileName &instance, const IOobjectOption::writeOption wOpt=IOobject::AUTO_WRITE)
Set the instance for mesh files.
Definition: polyMeshIO.C:29
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
const dimensionedScalar c
Speed of light in a vacuum.
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
const polyBoundaryMesh & patches
Nothing to be read.
Automatically write from objectRegistry::writeObject()
HashTable< label, labelPair, Foam::Hash< labelPair > > labelPairLookup
This is a Map of a labelPair to a label. Used for e.g. for face1, face2 to shared edge...
const std::string patch
OpenFOAM patch number as a std::string.
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.
"nonBlocking" : (MPI_Isend, MPI_Irecv)
messageStream Info
Information stream (stdout output on master, null elsewhere)
void writeCellAlignments(const fvMesh &mesh) const
Field< vector > vectorField
Specialisation of Field<T> for vector.
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return pointer to a new patch created on freestore from components.
Definition: polyPatchNew.C:28
const cvControls & foamyHexMeshControls() const
Return the foamyHexMeshControls object.
const Time & time() const
Return the Time object.
const volVectorField & C() const
Return cell centres as volVectorField.
double elapsedCpuTime() const
Return CPU time (in seconds) from the start.
Definition: cpuTimePosix.C:73
PtrList< dictionary > patchDicts
Definition: readKivaGrid.H:532
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
virtual bool write(const bool valid=true) const
Write using setting from DB.
void writeInternalDelaunayVertices(const fileName &instance, const Triangulation &t)
Write the internal Delaunay vertices of the tessellation as a.
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:458
IOList< label > labelIOList
Label container classes.
Definition: labelIOList.H:38
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157