conformalVoronoiMeshCalcDualMesh.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-2016 OpenFOAM Foundation
9  Copyright (C) 2018-2021 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 "motionSmoother.H"
32 #include "polyMeshGeometry.H"
33 #include "indexedCellChecks.H"
34 #include "OBJstream.H"
35 #include "indexedCellOps.H"
36 #include "ListOps.H"
37 #include "DelaunayMeshTools.H"
38 
39 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
40 
41 void Foam::conformalVoronoiMesh::calcDualMesh
42 (
44  labelList& boundaryPts,
45  faceList& faces,
46  labelList& owner,
47  labelList& neighbour,
49  PtrList<dictionary>& patchDicts,
50  pointField& cellCentres,
51  labelList& cellToDelaunayVertex,
52  labelListList& patchToDelaunayVertex,
53  bitSet& boundaryFacesToRemove
54 )
55 {
56  timeCheck("Start calcDualMesh");
57 
58  setVertexSizeAndAlignment();
59 
60  timeCheck("After setVertexSizeAndAlignment");
61 
62  indexDualVertices(points, boundaryPts);
63 
64  {
65  Info<< nl << "Merging identical points" << endl;
66 
67  // There is no guarantee that a merge of close points is no-risk
68  mergeIdenticalDualVertices(points, boundaryPts);
69  }
70 
71  // Final dual face and owner neighbour construction
72 
73  timeCheck("Before createFacesOwnerNeighbourAndPatches");
74 
75  createFacesOwnerNeighbourAndPatches
76  (
77  points,
78  faces,
79  owner,
80  neighbour,
81  patchNames,
82  patchDicts,
83  patchToDelaunayVertex, // from patch face to Delaunay vertex (slavePp)
84  boundaryFacesToRemove,
85  false
86  );
87 
88  // deferredCollapseFaceSet(owner, neighbour, deferredCollapseFaces);
89 
90  cellCentres = DelaunayMeshTools::allPoints(*this);
91 
92  cellToDelaunayVertex = removeUnusedCells(owner, neighbour);
93 
94  cellCentres = pointField(cellCentres, cellToDelaunayVertex);
95 
96  removeUnusedPoints(faces, points, boundaryPts);
97 
98  timeCheck("End of calcDualMesh");
99 }
100 
101 
102 void Foam::conformalVoronoiMesh::calcTetMesh
103 (
105  labelList& pointToDelaunayVertex,
106  faceList& faces,
107  labelList& owner,
108  labelList& neighbour,
110  PtrList<dictionary>& patchDicts
111 )
112 {
113  labelList vertexMap(number_of_vertices());
114 
115  label vertI = 0;
116 
117  points.setSize(number_of_vertices());
118  pointToDelaunayVertex.setSize(number_of_vertices());
119 
120  for
121  (
122  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
123  vit != finite_vertices_end();
124  ++vit
125  )
126  {
127  if (vit->internalPoint() || vit->boundaryPoint())
128  {
129  vertexMap[vit->index()] = vertI;
130  points[vertI] = topoint(vit->point());
131  pointToDelaunayVertex[vertI] = vit->index();
132  vertI++;
133  }
134  }
135 
136  points.setSize(vertI);
137  pointToDelaunayVertex.setSize(vertI);
138 
139  label celli = 0;
140 
141  for
142  (
143  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
144  cit != finite_cells_end();
145  ++cit
146  )
147  {
148  if (cit->internalOrBoundaryDualVertex())
149  {
150  cit->cellIndex() = celli++;
151  }
152  else
153  {
154  cit->cellIndex() = Cb::ctFar;
155  }
156  }
157 
158  patchNames = geometryToConformTo_.patchNames();
159 
160  patchNames.setSize(patchNames.size() + 1);
161 
162  patchNames[patchNames.size() - 1] = "foamyHexMesh_defaultPatch";
163 
164  label nPatches = patchNames.size();
165 
166  List<DynamicList<face>> patchFaces(nPatches, DynamicList<face>(0));
167 
168  List<DynamicList<label>> patchOwners(nPatches, DynamicList<label>(0));
169 
170  faces.setSize(number_of_finite_facets());
171 
172  owner.setSize(number_of_finite_facets());
173 
174  neighbour.setSize(number_of_finite_facets());
175 
176  label facei = 0;
177 
178  labelList verticesOnTriFace(3, label(-1));
179 
180  face newFace(verticesOnTriFace);
181 
182  for
183  (
184  Delaunay::Finite_facets_iterator fit = finite_facets_begin();
185  fit != finite_facets_end();
186  ++fit
187  )
188  {
189  const Cell_handle c1(fit->first);
190  const label oppositeVertex = fit->second;
191  const Cell_handle c2(c1->neighbor(oppositeVertex));
192 
193  if (c1->hasFarPoint() && c2->hasFarPoint())
194  {
195  // Both tets are outside, skip
196  continue;
197  }
198 
199  label c1I = c1->cellIndex();
200  label c2I = c2->cellIndex();
201 
202  label ownerCell = -1;
203  label neighbourCell = -1;
204 
205  for (label i = 0; i < 3; i++)
206  {
207  verticesOnTriFace[i] = vertexMap
208  [
209  c1->vertex(vertex_triple_index(oppositeVertex, i))->index()
210  ];
211  }
212 
213  newFace = face(verticesOnTriFace);
214 
215  if (c1->hasFarPoint() || c2->hasFarPoint())
216  {
217  // Boundary face...
218  if (c1->hasFarPoint())
219  {
220  //... with c1 outside
221  ownerCell = c2I;
222  }
223  else
224  {
225  // ... with c2 outside
226  ownerCell = c1I;
227 
228  reverse(newFace);
229  }
230 
231  label patchIndex = geometryToConformTo_.findPatch
232  (
233  newFace.centre(points)
234  );
235 
236  if (patchIndex == -1)
237  {
238  patchIndex = patchNames.size() - 1;
239 
241  << newFace.centre(points) << nl
242  << "did not find a surface patch. Adding to "
243  << patchNames[patchIndex]
244  << endl;
245  }
246 
247  patchFaces[patchIndex].append(newFace);
248  patchOwners[patchIndex].append(ownerCell);
249  }
250  else
251  {
252  // Internal face...
253  if (c1I < c2I)
254  {
255  // ...with c1 as the ownerCell
256  ownerCell = c1I;
257  neighbourCell = c2I;
258 
259  reverse(newFace);
260  }
261  else
262  {
263  // ...with c2 as the ownerCell
264  ownerCell = c2I;
265  neighbourCell = c1I;
266  }
267 
268  faces[facei] = newFace;
269  owner[facei] = ownerCell;
270  neighbour[facei] = neighbourCell;
271  facei++;
272  }
273  }
274 
275  label nInternalFaces = facei;
276 
277  faces.setSize(nInternalFaces);
278  owner.setSize(nInternalFaces);
279  neighbour.setSize(nInternalFaces);
280 
281  sortFaces(faces, owner, neighbour);
282 
283 // bitSet boundaryFacesToRemove;
284 // List<DynamicList<bool>> indirectPatchFace;
285 //
286 // addPatches
287 // (
288 // nInternalFaces,
289 // faces,
290 // owner,
291 // patchDicts,
292 // boundaryFacesToRemove,
293 // patchFaces,
294 // patchOwners,
295 // indirectPatchFace
296 // );
297 }
298 
299 
300 void Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
301 (
302  const pointField& pts,
303  labelList& boundaryPts
304 )
305 {
306  // Assess close points to be merged
307 
308  label nPtsMerged = 0;
309  label nPtsMergedSum = 0;
310 
311  do
312  {
313  Map<label> dualPtIndexMap;
314 
315  nPtsMerged = mergeIdenticalDualVertices
316  (
317  pts,
318  dualPtIndexMap
319  );
320 
321  reindexDualVertices(dualPtIndexMap, boundaryPts);
322 
323  reduce(nPtsMerged, sumOp<label>());
324 
325  nPtsMergedSum += nPtsMerged;
326 
327  } while (nPtsMerged > 0);
328 
329  if (nPtsMergedSum > 0)
330  {
331  Info<< " Merged " << nPtsMergedSum << " points " << endl;
332  }
333 }
334 
335 
336 Foam::label Foam::conformalVoronoiMesh::mergeIdenticalDualVertices
337 (
338  const pointField& pts,
339  Map<label>& dualPtIndexMap
340 ) const
341 {
342  label nPtsMerged = 0;
343 
344  for
345  (
346  Delaunay::Finite_facets_iterator fit = finite_facets_begin();
347  fit != finite_facets_end();
348  ++fit
349  )
350  {
351  const Cell_handle c1(fit->first);
352  const label oppositeVertex = fit->second;
353  const Cell_handle c2(c1->neighbor(oppositeVertex));
354 
355  if (is_infinite(c1) || is_infinite(c2))
356  {
357  continue;
358  }
359 
360  label& c1I = c1->cellIndex();
361  label& c2I = c2->cellIndex();
362 
363  if ((c1I != c2I) && !c1->hasFarPoint() && !c2->hasFarPoint())
364  {
365  const Foam::point& p1 = pts[c1I];
366  const Foam::point& p2 = pts[c2I];
367 
368  if (p1 == p2)
369  {
370 // if (c1->parallelDualVertex() || c2->parallelDualVertex())
371 // {
372 // if (c1->vertexLowestProc() < c2->vertexLowestProc())
373 // {
374 // dualPtIndexMap.insert(c1I, c1I);
375 // dualPtIndexMap.insert(c2I, c1I);
376 // }
377 // else
378 // {
379 // dualPtIndexMap.insert(c1I, c2I);
380 // dualPtIndexMap.insert(c2I, c2I);
381 // }
382 // }
383  if (c1I < c2I)
384  {
385  dualPtIndexMap.insert(c1I, c1I);
386  dualPtIndexMap.insert(c2I, c1I);
387  }
388  else
389  {
390  dualPtIndexMap.insert(c1I, c2I);
391  dualPtIndexMap.insert(c2I, c2I);
392  }
393 
394  nPtsMerged++;
395  }
396  }
397  }
398 
399  if (debug)
400  {
401  Info<< "mergeIdenticalDualVertices:" << endl
402  << " zero-length edges : "
403  << returnReduce(nPtsMerged, sumOp<label>()) << endl
404  << endl;
405  }
406 
407  return nPtsMerged;
408 }
409 
410 
411 //void Foam::conformalVoronoiMesh::smoothSurface
412 //(
413 // pointField& pts,
414 // const labelList& boundaryPts
415 //)
416 //{
417 // label nCollapsedFaces = 0;
418 //
419 // label iterI = 0;
420 //
421 // do
422 // {
423 // Map<label> dualPtIndexMap;
424 //
425 // nCollapsedFaces = smoothSurfaceDualFaces
426 // (
427 // pts,
428 // boundaryPts,
429 // dualPtIndexMap
430 // );
431 //
432 // reduce(nCollapsedFaces, sumOp<label>());
433 //
434 // reindexDualVertices(dualPtIndexMap);
435 //
436 // mergeIdenticalDualVertices(pts, boundaryPts);
437 //
438 // if (nCollapsedFaces > 0)
439 // {
440 // Info<< " Collapsed " << nCollapsedFaces << " boundary faces"
441 // << endl;
442 // }
443 //
444 // if (++iterI > foamyHexMeshControls().maxCollapseIterations())
445 // {
446 // Info<< " maxCollapseIterations reached, stopping collapse"
447 // << endl;
448 //
449 // break;
450 // }
451 //
452 // } while (nCollapsedFaces > 0);
453 //
454 // // Force all points of boundary faces to be on the surface
505 //}
506 //
507 //
508 //Foam::label Foam::conformalVoronoiMesh::smoothSurfaceDualFaces
509 //(
510 // pointField& pts,
511 // const labelList& boundaryPts,
512 // Map<label>& dualPtIndexMap
513 //) const
514 //{
515 // label nCollapsedFaces = 0;
516 //
517 // const scalar cosPerpendicularToleranceAngle = cos
518 // (
519 // degToRad(foamyHexMeshControls().surfaceStepFaceAngle())
520 // );
521 //
522 // for
523 // (
524 // Delaunay::Finite_edges_iterator eit = finite_edges_begin();
525 // eit != finite_edges_end();
526 // ++eit
527 // )
528 // {
529 // Cell_circulator ccStart = incident_cells(*eit);
530 // Cell_circulator cc = ccStart;
531 //
532 // bool skipFace = false;
533 //
534 // do
535 // {
536 // if (dualPtIndexMap.found(cc->cellIndex()))
537 // {
538 // // One of the points of this face has already been
539 // // collapsed this sweep, leave for next sweep
540 //
541 // skipFace = true;
542 //
543 // break;
544 // }
545 //
546 // } while (++cc != ccStart);
547 //
548 // if (skipFace)
549 // {
550 // continue;
551 // }
552 //
553 // if (isBoundaryDualFace(eit))
554 // {
555 // face dualFace = buildDualFace(eit);
556 //
557 // if (dualFace.size() < 3)
558 // {
559 // // This face has been collapsed already
560 // continue;
561 // }
562 //
563 // label maxFC = maxFilterCount(eit);
564 //
565 // if (maxFC > foamyHexMeshControls().filterCountSkipThreshold())
566 // {
567 // // A vertex on this face has been limited too many
568 // // times, skip
569 // continue;
570 // }
571 //
572 // Cell_handle c = eit->first;
573 // Vertex_handle vA = c->vertex(eit->second);
574 // Vertex_handle vB = c->vertex(eit->third);
575 //
576 // if
577 // (
578 // vA->internalBoundaryPoint() && vA->surfacePoint()
579 // && vB->externalBoundaryPoint() && vB->surfacePoint()
580 // )
581 // {
582 // if (vA->index() == vB->index() - 1)
583 // {
584 // continue;
585 // }
586 // }
587 // else if
588 // (
589 // vA->externalBoundaryPoint() && vA->surfacePoint()
590 // && vB->internalBoundaryPoint() && vB->surfacePoint()
591 // )
592 // {
593 // if (vA->index() == vB->index() + 1)
594 // {
595 // continue;
596 // }
597 // }
642 //
643 //
644 // if ((faceNormal & surfaceNormal) < cosPerpendicularToleranceAngle)
645 // {
646 // scalar targetFaceSize = averageAnyCellSize(vA, vB);
647 //
648 // // Selecting faces to collapse based on angle to
649 // // surface, so set collapseSizeLimitCoeff to GREAT to
650 // // allow collapse of all faces
651 //
652 // faceCollapseMode mode = collapseFace
653 // (
654 // dualFace,
655 // pts,
656 // boundaryPts,
657 // dualPtIndexMap,
658 // targetFaceSize,
659 // GREAT,
660 // maxFC
661 // );
662 //
663 // if (mode == fcmPoint || mode == fcmEdge)
664 // {
665 // nCollapsedFaces++;
666 // }
667 // }
668 // }
669 // }
670 //
671 // return nCollapsedFaces;
672 //}
673 
674 
675 void Foam::conformalVoronoiMesh::deferredCollapseFaceSet
676 (
677  labelList& owner,
678  labelList& neighbour,
679  const labelPairHashSet& deferredCollapseFaces
680 ) const
681 {
682  DynamicList<label> faceLabels;
683 
684  forAll(neighbour, nI)
685  {
686  if (deferredCollapseFaces.found(Pair<label>(owner[nI], neighbour[nI])))
687  {
688  faceLabels.append(nI);
689  }
690  }
691 
692  Pout<< "facesToCollapse" << nl << faceLabels << endl;
693 }
694 
695 
697 Foam::conformalVoronoiMesh::createPolyMeshFromPoints
698 (
699  const pointField& pts
700 ) const
701 {
702  faceList faces;
703  labelList owner;
704  labelList neighbour;
706  PtrList<dictionary> patchDicts;
707  pointField cellCentres;
708  labelListList patchToDelaunayVertex;
709  bitSet boundaryFacesToRemove;
710 
711  timeCheck("Start of checkPolyMeshQuality");
712 
713  Info<< nl << "Creating polyMesh to assess quality" << endl;
714 
715  createFacesOwnerNeighbourAndPatches
716  (
717  pts,
718  faces,
719  owner,
720  neighbour,
721  patchNames,
722  patchDicts,
723  patchToDelaunayVertex,
724  boundaryFacesToRemove,
725  false
726  );
727 
728  cellCentres = DelaunayMeshTools::allPoints(*this);
729 
730  labelList cellToDelaunayVertex(removeUnusedCells(owner, neighbour));
731  cellCentres = pointField(cellCentres, cellToDelaunayVertex);
732 
734  (
735  IOobject
736  (
737  "foamyHexMesh_temporary",
738  runTime_.timeName(),
739  runTime_,
742  ),
743  pointField(pts), // Copy of points
744  std::move(faces),
745  std::move(owner),
746  std::move(neighbour)
747  );
748 
749  polyMesh& pMesh = meshPtr();
750 
751  List<polyPatch*> patches(patchNames.size());
752 
753  label nValidPatches = 0;
754 
755  forAll(patches, p)
756  {
757  label totalPatchSize = patchDicts[p].get<label>("nFaces");
758 
759  if
760  (
761  patchDicts.set(p)
762  && patchDicts[p].get<word>("type") == processorPolyPatch::typeName
763  )
764  {
765  // Do not create empty processor patches
766  if (totalPatchSize > 0)
767  {
768  patchDicts[p].set("transform", "coincidentFullMatch");
769 
770  patches[nValidPatches] = new processorPolyPatch
771  (
772  patchNames[p],
773  patchDicts[p],
774  nValidPatches,
775  pMesh.boundaryMesh(),
776  processorPolyPatch::typeName
777  );
778 
779  nValidPatches++;
780  }
781  }
782  else
783  {
784  // Check that the patch is not empty on every processor
785  reduce(totalPatchSize, sumOp<label>());
786 
787  if (totalPatchSize > 0)
788  {
789  patches[nValidPatches] = polyPatch::New
790  (
791  patchNames[p],
792  patchDicts[p],
793  nValidPatches,
794  pMesh.boundaryMesh()
795  ).ptr();
796 
797  nValidPatches++;
798  }
799  }
800  }
801 
802  patches.setSize(nValidPatches);
803 
804  pMesh.addPatches(patches);
805 
806  return meshPtr;
807 }
808 
809 
810 void Foam::conformalVoronoiMesh::checkCellSizing()
811 {
812  Info<< "Checking cell sizes..."<< endl;
813 
814  timeCheck("Start of Cell Sizing");
815 
816  labelList boundaryPts(number_of_finite_cells(), internal);
817  pointField ptsField;
818 
819  indexDualVertices(ptsField, boundaryPts);
820 
821  // Merge close dual vertices.
822  mergeIdenticalDualVertices(ptsField, boundaryPts);
823 
824  autoPtr<polyMesh> meshPtr = createPolyMeshFromPoints(ptsField);
825  const polyMesh& pMesh = meshPtr();
826 
827  //pMesh.write();
828 
829  // Find cells with poor quality
830  DynamicList<label> checkFaces(identity(pMesh.nFaces()));
831  labelHashSet wrongFaces(pMesh.nFaces()/100);
832 
833  Info<< "Running checkMesh on mesh with " << pMesh.nCells()
834  << " cells "<< endl;
835 
836  const dictionary& dict
837  = foamyHexMeshControls().foamyHexMeshDict();
838 
839  const dictionary& meshQualityDict
840  = dict.subDict("meshQualityControls");
841 
842  const scalar maxNonOrtho =
843  meshQualityDict.get<scalar>("maxNonOrtho", keyType::REGEX_RECURSIVE);
844 
845  label nWrongFaces = 0;
846 
847  if (maxNonOrtho < 180.0 - SMALL)
848  {
850  (
851  false,
852  maxNonOrtho,
853  pMesh,
854  pMesh.cellCentres(),
855  pMesh.faceAreas(),
856  checkFaces,
857  List<labelPair>(),
858  &wrongFaces
859  );
860 
861  label nNonOrthogonal = returnReduce(wrongFaces.size(), sumOp<label>());
862 
863  Info<< " non-orthogonality > " << maxNonOrtho
864  << " degrees : " << nNonOrthogonal << endl;
865 
866  nWrongFaces += nNonOrthogonal;
867  }
868 
869  labelHashSet protrudingCells = findOffsetPatchFaces(pMesh, 0.25);
870 
871  label nProtrudingCells = protrudingCells.size();
872 
873  Info<< " protruding/intruding cells : " << nProtrudingCells << endl;
874 
875  nWrongFaces += nProtrudingCells;
876 
877 // motionSmoother::checkMesh
878 // (
879 // false,
880 // pMesh,
881 // meshQualityDict,
882 // checkFaces,
883 // wrongFaces
884 // );
885 
886  Info<< " Found total of " << nWrongFaces << " bad faces" << endl;
887 
888  {
889  labelHashSet cellsToResizeMap(pMesh.nFaces()/100);
890 
891  // Find cells that are attached to the faces in wrongFaces.
892  for (const label facei : wrongFaces)
893  {
894  const label faceOwner = pMesh.faceOwner()[facei];
895  const label faceNeighbour = pMesh.faceNeighbour()[facei];
896 
897  cellsToResizeMap.insert(faceOwner);
898  cellsToResizeMap.insert(faceNeighbour);
899  }
900 
901  cellsToResizeMap += protrudingCells;
902 
903  pointField cellsToResize(cellsToResizeMap.size());
904 
905  label count = 0;
906  for (label celli = 0; celli < pMesh.nCells(); ++celli)
907  {
908  if (cellsToResizeMap.found(celli))
909  {
910  cellsToResize[count++] = pMesh.cellCentres()[celli];
911  }
912  }
913 
914  Info<< " DISABLED: Automatically re-sizing " << cellsToResize.size()
915  << " cells that are attached to the bad faces: " << endl;
916 
917  //cellSizeControl_.setCellSizes(cellsToResize);
918  }
919 
920  timeCheck("End of Cell Sizing");
921 
922  Info<< "Finished checking cell sizes"<< endl;
923 }
924 
925 
926 Foam::labelHashSet Foam::conformalVoronoiMesh::findOffsetPatchFaces
927 (
928  const polyMesh& mesh,
929  const scalar allowedOffset
930 ) const
931 {
932  timeCheck("Start findRemainingProtrusionSet");
933 
934  const polyBoundaryMesh& patches = mesh.boundaryMesh();
935 
936  cellSet offsetBoundaryCells
937  (
938  mesh,
939  "foamyHexMesh_protrudingCells",
940  mesh.nCells()/1000
941  );
942 
943  forAll(patches, patchi)
944  {
945  const polyPatch& patch = patches[patchi];
946 
947  const faceList& localFaces = patch.localFaces();
948  const pointField& localPoints = patch.localPoints();
949 
950  const labelList& fCell = patch.faceCells();
951 
952  forAll(localFaces, pLFI)
953  {
954  const face& f = localFaces[pLFI];
955 
956  const Foam::point& faceCentre = f.centre(localPoints);
957 
958  const scalar targetSize = targetCellSize(faceCentre);
959 
960  pointIndexHit pHit;
961  label surfHit = -1;
962 
963  geometryToConformTo_.findSurfaceNearest
964  (
965  faceCentre,
966  sqr(targetSize),
967  pHit,
968  surfHit
969  );
970 
971  if
972  (
973  pHit.hit()
974  && (mag(pHit.hitPoint() - faceCentre) > allowedOffset*targetSize)
975  )
976  {
977  offsetBoundaryCells.insert(fCell[pLFI]);
978  }
979  }
980  }
981 
982  if (foamyHexMeshControls().objOutput())
983  {
984  offsetBoundaryCells.write();
985  }
986 
987  return std::move(offsetBoundaryCells);
988 }
989 
990 
991 Foam::labelHashSet Foam::conformalVoronoiMesh::checkPolyMeshQuality
992 (
993  const pointField& pts
994 ) const
995 {
996  autoPtr<polyMesh> meshPtr = createPolyMeshFromPoints(pts);
997  polyMesh& pMesh = meshPtr();
998 
999  timeCheck("polyMesh created, checking quality");
1000 
1001  labelHashSet wrongFaces(pMesh.nFaces()/100);
1002 
1003  DynamicList<label> checkFaces(pMesh.nFaces());
1004 
1005  const vectorField& fAreas = pMesh.faceAreas();
1006 
1007  scalar faceAreaLimit = SMALL;
1008 
1009  forAll(fAreas, fI)
1010  {
1011  if (mag(fAreas[fI]) > faceAreaLimit)
1012  {
1013  checkFaces.append(fI);
1014  }
1015  }
1016 
1017  Info<< nl << "Excluding "
1018  << returnReduce(fAreas.size() - checkFaces.size(), sumOp<label>())
1019  << " faces from check, < " << faceAreaLimit << " area" << endl;
1020 
1021  const dictionary& dict
1022  = foamyHexMeshControls().foamyHexMeshDict();
1023 
1024  const dictionary& meshQualityDict
1025  = dict.subDict("meshQualityControls");
1026 
1028  (
1029  false,
1030  pMesh,
1031  meshQualityDict,
1032  checkFaces,
1033  wrongFaces
1034  );
1035 
1036  {
1037  // Check for cells with more than 1 but fewer than 4 faces
1038  label nInvalidPolyhedra = 0;
1039 
1040  const cellList& cells = pMesh.cells();
1041 
1042  forAll(cells, cI)
1043  {
1044  if (cells[cI].size() < 4 && cells[cI].size() > 0)
1045  {
1046  // Pout<< "cell " << cI << " " << cells[cI]
1047  // << " has " << cells[cI].size() << " faces."
1048  // << endl;
1049 
1050  nInvalidPolyhedra++;
1051 
1052  wrongFaces.insert(cells[cI]);
1053  }
1054  }
1055 
1056  Info<< " cells with more than 1 but fewer than 4 faces : "
1057  << returnReduce(nInvalidPolyhedra, sumOp<label>())
1058  << endl;
1059 
1060  // Check for cells with one internal face only
1061 
1062  labelList nInternalFaces(pMesh.nCells(), Zero);
1063 
1064  for (label fI = 0; fI < pMesh.nInternalFaces(); fI++)
1065  {
1066  nInternalFaces[pMesh.faceOwner()[fI]]++;
1067  nInternalFaces[pMesh.faceNeighbour()[fI]]++;
1068  }
1069 
1070  const polyBoundaryMesh& patches = pMesh.boundaryMesh();
1071 
1072  forAll(patches, patchi)
1073  {
1074  if (patches[patchi].coupled())
1075  {
1076  const labelUList& owners = patches[patchi].faceCells();
1077 
1078  forAll(owners, i)
1079  {
1080  nInternalFaces[owners[i]]++;
1081  }
1082  }
1083  }
1084 
1085  label oneInternalFaceCells = 0;
1086 
1087  forAll(nInternalFaces, cI)
1088  {
1089  if (nInternalFaces[cI] <= 1)
1090  {
1091  oneInternalFaceCells++;
1092  wrongFaces.insert(cells[cI]);
1093  }
1094  }
1095 
1096  Info<< " cells with with zero or one non-boundary face : "
1097  << returnReduce(oneInternalFaceCells, sumOp<label>())
1098  << endl;
1099  }
1100 
1101 
1102  bitSet ptToBeLimited(pts.size(), false);
1103 
1104  for (const label facei : wrongFaces)
1105  {
1106  const face f = pMesh.faces()[facei];
1107 
1108  ptToBeLimited.set(f);
1109  }
1110 
1111  // // Limit connected cells
1112 
1113  // labelHashSet limitCells(pMesh.nCells()/100);
1114 
1115  // const labelListList& ptCells = pMesh.pointCells();
1116 
1117  // for (const label facei : wrongFaces)
1118  // {
1119  // const face f = pMesh.faces()[facei];
1120 
1121  // forAll(f, fPtI)
1122  // {
1123  // label ptI = f[fPtI];
1124  // const labelList& pC = ptCells[ptI];
1125  // limitCells.insert(pC);
1126  // }
1127  // }
1128 
1129  // const labelListList& cellPts = pMesh.cellPoints();
1130 
1131  // for (const label celli : limitCells)
1132  // {
1133  // const labelList& cP = cellPts[celli];
1134 
1135  // ptToBeLimited.set(cP);
1136  // }
1137 
1138 
1139  // Apply Delaunay cell filterCounts and determine the maximum
1140  // overall filterCount
1141 
1142  label maxFilterCount = 0;
1143 
1144  for
1145  (
1146  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1147  cit != finite_cells_end();
1148  ++cit
1149  )
1150  {
1151  label cI = cit->cellIndex();
1152 
1153  if (cI >= 0)
1154  {
1155  if (ptToBeLimited.test(cI))
1156  {
1157  cit->filterCount()++;
1158  }
1159 
1160  if (cit->filterCount() > maxFilterCount)
1161  {
1162  maxFilterCount = cit->filterCount();
1163  }
1164  }
1165  }
1166 
1167  Info<< nl << "Maximum number of filter limits applied: "
1168  << returnReduce(maxFilterCount, maxOp<label>()) << endl;
1169 
1170  return wrongFaces;
1171 }
1172 
1173 
1174 Foam::label Foam::conformalVoronoiMesh::classifyBoundaryPoint
1175 (
1176  Cell_handle cit
1177 ) const
1178 {
1179  if (cit->boundaryDualVertex())
1180  {
1181  if (cit->featurePointDualVertex())
1182  {
1183  return featurePoint;
1184  }
1185  else if (cit->featureEdgeDualVertex())
1186  {
1187  return featureEdge;
1188  }
1189  else
1190  {
1191  return surface;
1192  }
1193  }
1194  else if (cit->baffleSurfaceDualVertex())
1195  {
1196  return surface;
1197  }
1198  else if (cit->baffleEdgeDualVertex())
1199  {
1200  return featureEdge;
1201  }
1202  else
1203  {
1204  return internal;
1205  }
1206 }
1207 
1208 
1209 void Foam::conformalVoronoiMesh::indexDualVertices
1210 (
1211  pointField& pts,
1212  labelList& boundaryPts
1213 )
1214 {
1215  // Indexing Delaunay cells, which are the dual vertices
1216 
1217  this->resetCellCount();
1218 
1219  label nConstrainedVertices = 0;
1220  if (foamyHexMeshControls().guardFeaturePoints())
1221  {
1222  for
1223  (
1224  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1225  vit != finite_vertices_end();
1226  ++vit
1227  )
1228  {
1229  if (vit->constrained())
1230  {
1231  vit->index() = number_of_finite_cells() + nConstrainedVertices;
1232  nConstrainedVertices++;
1233  }
1234  }
1235  }
1236 
1237  pts.setSize(number_of_finite_cells() + nConstrainedVertices);
1238  boundaryPts.setSize
1239  (
1240  number_of_finite_cells() + nConstrainedVertices,
1241  internal
1242  );
1243 
1244  if (foamyHexMeshControls().guardFeaturePoints())
1245  {
1246  nConstrainedVertices = 0;
1247  for
1248  (
1249  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1250  vit != finite_vertices_end();
1251  ++vit
1252  )
1253  {
1254  if (vit->constrained())
1255  {
1256  pts[number_of_finite_cells() + nConstrainedVertices] =
1257  topoint(vit->point());
1258 
1259  boundaryPts[number_of_finite_cells() + nConstrainedVertices] =
1260  constrained;
1261 
1262  nConstrainedVertices++;
1263  }
1264  }
1265  }
1266 
1267  //OBJstream snapping1("snapToSurface1.obj");
1268  //OBJstream snapping2("snapToSurface2.obj");
1269  //OFstream tetToSnapTo("tetsToSnapTo.obj");
1270 
1271  for
1272  (
1273  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1274  cit != finite_cells_end();
1275  ++cit
1276  )
1277  {
1278 // if (tetrahedron(cit).volume() == 0)
1279 // {
1280 // Pout<< "ZERO VOLUME TET" << endl;
1281 // Pout<< cit->info();
1282 // Pout<< "Dual = " << cit->dual();
1283 // }
1284 
1285  if (!cit->hasFarPoint())
1286  {
1287  cit->cellIndex() = getNewCellIndex();
1288 
1289  // For nearly coplanar Delaunay cells that are present on different
1290  // processors the result of the circumcentre calculation depends on
1291  // the ordering of the vertices, so synchronise it across processors
1292 
1293  if (Pstream::parRun() && cit->parallelDualVertex())
1294  {
1295  typedef CGAL::Exact_predicates_exact_constructions_kernel Exact;
1296  typedef CGAL::Point_3<Exact> ExactPoint;
1297 
1298  List<labelPair> cellVerticesPair(4);
1299  List<ExactPoint> cellVertices(4);
1300 
1301  for (label vI = 0; vI < 4; ++vI)
1302  {
1303  cellVerticesPair[vI] = labelPair
1304  (
1305  cit->vertex(vI)->procIndex(),
1306  cit->vertex(vI)->index()
1307  );
1308 
1309  cellVertices[vI] = ExactPoint
1310  (
1311  cit->vertex(vI)->point().x(),
1312  cit->vertex(vI)->point().y(),
1313  cit->vertex(vI)->point().z()
1314  );
1315  }
1316 
1317  // Sort the vertices so that they will be in the same order on
1318  // each processor
1319  labelList oldToNew(sortedOrder(cellVerticesPair));
1320  oldToNew = invert(oldToNew.size(), oldToNew);
1321  inplaceReorder(oldToNew, cellVertices);
1322 
1323  ExactPoint synchronisedDual = CGAL::circumcenter
1324  (
1325  cellVertices[0],
1326  cellVertices[1],
1327  cellVertices[2],
1328  cellVertices[3]
1329  );
1330 
1331  pts[cit->cellIndex()] = Foam::point
1332  (
1333  CGAL::to_double(synchronisedDual.x()),
1334  CGAL::to_double(synchronisedDual.y()),
1335  CGAL::to_double(synchronisedDual.z())
1336  );
1337  }
1338  else
1339  {
1340  pts[cit->cellIndex()] = cit->dual();
1341  }
1342 
1343  // Feature point snapping
1344  if (foamyHexMeshControls().snapFeaturePoints())
1345  {
1346  if (cit->featurePointDualVertex())
1347  {
1348  pointFromPoint dual = cit->dual();
1349 
1350  pointIndexHit fpHit;
1351  label featureHit;
1352 
1353  // Find nearest feature point and compare
1354  geometryToConformTo_.findFeaturePointNearest
1355  (
1356  dual,
1357  sqr(targetCellSize(dual)),
1358  fpHit,
1359  featureHit
1360  );
1361 
1362  if (fpHit.hit())
1363  {
1364  if (debug)
1365  {
1366  Info<< "Dual = " << dual << nl
1367  << " Nearest = " << fpHit.hitPoint() << endl;
1368  }
1369 
1370  pts[cit->cellIndex()] = fpHit.hitPoint();
1371  }
1372  }
1373  }
1374 
1375 // {
1376 // // Snapping points far outside
1377 // if (cit->boundaryDualVertex() && !cit->parallelDualVertex())
1378 // {
1379 // pointFromPoint dual = cit->dual();
1380 //
1381 // pointIndexHit hitInfo;
1382 // label surfHit;
1383 //
1384 // // Find nearest surface point
1385 // geometryToConformTo_.findSurfaceNearest
1386 // (
1387 // dual,
1388 // sqr(targetCellSize(dual)),
1389 // hitInfo,
1390 // surfHit
1391 // );
1392 //
1393 // if (!hitInfo.hit())
1394 // {
1395 // // Project dual to nearest point on tet
1396 //
1397 // tetPointRef tet
1398 // (
1399 // topoint(cit->vertex(0)->point()),
1400 // topoint(cit->vertex(1)->point()),
1401 // topoint(cit->vertex(2)->point()),
1402 // topoint(cit->vertex(3)->point())
1403 // );
1404 //
1405 // pointFromPoint nearestPointOnTet =
1406 // tet.nearestPoint(dual).rawPoint();
1407 //
1408 // // Get nearest point on surface from tet.
1409 // geometryToConformTo_.findSurfaceNearest
1410 // (
1411 // nearestPointOnTet,
1412 // sqr(targetCellSize(nearestPointOnTet)),
1413 // hitInfo,
1414 // surfHit
1415 // );
1416 //
1417 // vector snapDir = nearestPointOnTet - dual;
1418 // snapDir /= mag(snapDir) + SMALL;
1419 //
1420 // drawDelaunayCell(tetToSnapTo, cit, offset);
1421 // offset += 1;
1422 //
1423 // vectorField norm(1);
1424 // allGeometry_[surfHit].getNormal
1425 // (
1426 // List<pointIndexHit>(1, hitInfo),
1427 // norm
1428 // );
1429 // norm[0] /= mag(norm[0]) + SMALL;
1430 //
1431 // if
1432 // (
1433 // hitInfo.hit()
1434 // && (mag(snapDir & norm[0]) > 0.5)
1435 // )
1436 // {
1437 // snapping1.write
1438 // (
1439 // linePointRef(dual, nearestPointOnTet)
1440 // );
1441 //
1442 // snapping2.write
1443 // (
1444 // linePointRef
1445 // (
1446 // nearestPointOnTet,
1447 // hitInfo.hitPoint()
1448 // )
1449 // );
1450 //
1451 // pts[cit->cellIndex()] = hitInfo.hitPoint();
1452 // }
1453 // }
1454 // }
1455 // }
1456 
1457  boundaryPts[cit->cellIndex()] = classifyBoundaryPoint(cit);
1458  }
1459  else
1460  {
1461  cit->cellIndex() = Cb::ctFar;
1462  }
1463  }
1464 
1465  //pts.setSize(this->cellCount());
1466 
1467  //boundaryPts.setSize(this->cellCount());
1468 }
1469 
1470 
1471 void Foam::conformalVoronoiMesh::reindexDualVertices
1472 (
1473  const Map<label>& dualPtIndexMap,
1474  labelList& boundaryPts
1475 )
1476 {
1477  for
1478  (
1479  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1480  cit != finite_cells_end();
1481  ++cit
1482  )
1483  {
1484  if (dualPtIndexMap.found(cit->cellIndex()))
1485  {
1486  cit->cellIndex() = dualPtIndexMap[cit->cellIndex()];
1487  boundaryPts[cit->cellIndex()] =
1488  max
1489  (
1490  boundaryPts[cit->cellIndex()],
1491  boundaryPts[dualPtIndexMap[cit->cellIndex()]]
1492  );
1493  }
1494  }
1495 }
1496 
1497 
1498 Foam::label Foam::conformalVoronoiMesh::createPatchInfo
1499 (
1501  PtrList<dictionary>& patchDicts
1502 ) const
1503 {
1504  patchNames = geometryToConformTo_.patchNames();
1505 
1506  patchDicts.setSize(patchNames.size() + 1);
1507 
1508  const PtrList<dictionary>& patchInfo = geometryToConformTo_.patchInfo();
1509 
1510  forAll(patchNames, patchi)
1511  {
1512  if (patchInfo.set(patchi))
1513  {
1514  patchDicts.set(patchi, new dictionary(patchInfo[patchi]));
1515  }
1516  else
1517  {
1518  patchDicts.set(patchi, new dictionary());
1519  patchDicts[patchi].set
1520  (
1521  "type",
1522  wallPolyPatch::typeName
1523  );
1524  }
1525  }
1526 
1527  patchNames.setSize(patchNames.size() + 1);
1528  label defaultPatchIndex = patchNames.size() - 1;
1529  patchNames[defaultPatchIndex] = "foamyHexMesh_defaultPatch";
1530  patchDicts.set(defaultPatchIndex, new dictionary());
1531  patchDicts[defaultPatchIndex].set
1532  (
1533  "type",
1534  wallPolyPatch::typeName
1535  );
1536 
1537  label nProcPatches = 0;
1538 
1539  if (Pstream::parRun())
1540  {
1541  List<boolList> procUsedList
1542  (
1543  Pstream::nProcs(),
1544  boolList(Pstream::nProcs(), false)
1545  );
1546 
1547  boolList& procUsed = procUsedList[Pstream::myProcNo()];
1548 
1549  // Determine which processor patches are required
1550  for
1551  (
1552  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1553  vit != finite_vertices_end();
1554  vit++
1555  )
1556  {
1557  // This test is not sufficient if one of the processors does
1558  // not receive a referred vertex from another processor, but does
1559  // send one to the other processor.
1560  if (vit->referred())
1561  {
1562  procUsed[vit->procIndex()] = true;
1563  }
1564  }
1565 
1566  // Because the previous test was insufficient, combine the lists.
1567  Pstream::gatherList(procUsedList);
1568  Pstream::scatterList(procUsedList);
1569 
1570  forAll(procUsedList, proci)
1571  {
1572  if (proci != Pstream::myProcNo())
1573  {
1574  if (procUsedList[proci][Pstream::myProcNo()])
1575  {
1576  procUsed[proci] = true;
1577  }
1578  }
1579  }
1580 
1581  forAll(procUsed, pUI)
1582  {
1583  if (procUsed[pUI])
1584  {
1585  nProcPatches++;
1586  }
1587  }
1588 
1589  label nNonProcPatches = patchNames.size();
1590  label nTotalPatches = nNonProcPatches + nProcPatches;
1591 
1592  patchNames.setSize(nTotalPatches);
1593  patchDicts.setSize(nTotalPatches);
1594  for (label pI = nNonProcPatches; pI < nTotalPatches; ++pI)
1595  {
1596  patchDicts.set(pI, new dictionary());
1597  }
1598 
1599  label procAddI = 0;
1600 
1601  forAll(procUsed, pUI)
1602  {
1603  if (procUsed[pUI])
1604  {
1605  patchNames[nNonProcPatches + procAddI] =
1607 
1608  patchDicts[nNonProcPatches + procAddI].set
1609  (
1610  "type",
1611  processorPolyPatch::typeName
1612  );
1613 
1614  patchDicts[nNonProcPatches + procAddI].set
1615  (
1616  "myProcNo",
1618  );
1619 
1620  patchDicts[nNonProcPatches + procAddI].set("neighbProcNo", pUI);
1621 
1622  procAddI++;
1623  }
1624  }
1625  }
1626 
1627  return defaultPatchIndex;
1628 }
1629 
1630 
1631 Foam::vector Foam::conformalVoronoiMesh::calcSharedPatchNormal
1632 (
1633  Cell_handle c1,
1634  Cell_handle c2
1635 ) const
1636 {
1637  List<Foam::point> patchEdge(2, point::max);
1638 
1639  // Get shared Facet
1640  for (label cI = 0; cI < 4; ++cI)
1641  {
1642  if (c1->neighbor(cI) != c2 && !c1->vertex(cI)->constrained())
1643  {
1644  if (c1->vertex(cI)->internalBoundaryPoint())
1645  {
1646  patchEdge[0] = topoint(c1->vertex(cI)->point());
1647  }
1648  else
1649  {
1650  patchEdge[1] = topoint(c1->vertex(cI)->point());
1651  }
1652  }
1653  }
1654 
1655  Info<< " " << patchEdge << endl;
1656 
1657  return vector(patchEdge[1] - patchEdge[0]);
1658 }
1659 
1660 
1661 bool Foam::conformalVoronoiMesh::boundaryDualFace
1662 (
1663  Cell_handle c1,
1664  Cell_handle c2
1665 ) const
1666 {
1667  label nInternal = 0;
1668  label nExternal = 0;
1669 
1670  for (label cI = 0; cI < 4; ++cI)
1671  {
1672  if (c1->neighbor(cI) != c2 && !c1->vertex(cI)->constrained())
1673  {
1674  if (c1->vertex(cI)->internalBoundaryPoint())
1675  {
1676  nInternal++;
1677  }
1678  else if (c1->vertex(cI)->externalBoundaryPoint())
1679  {
1680  nExternal++;
1681  }
1682  }
1683  }
1684 
1685  Info<< "in = " << nInternal << " out = " << nExternal << endl;
1686 
1687  return (nInternal == 1 && nExternal == 1);
1688 }
1689 
1690 
1691 void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches
1692 (
1693  const pointField& pts,
1694  faceList& faces,
1695  labelList& owner,
1696  labelList& neighbour,
1698  PtrList<dictionary>& patchDicts,
1699  labelListList& patchPointPairSlaves,
1700  bitSet& boundaryFacesToRemove,
1701  bool includeEmptyPatches
1702 ) const
1703 {
1704  const label defaultPatchIndex = createPatchInfo(patchNames, patchDicts);
1705 
1706  const label nPatches = patchNames.size();
1707 
1708  labelList procNeighbours(nPatches);
1709  forAll(procNeighbours, patchi)
1710  {
1711  procNeighbours[patchi] =
1712  patchDicts[patchi].getOrDefault<label>("neighbProcNo", -1);
1713  }
1714 
1715  List<DynamicList<face>> patchFaces(nPatches, DynamicList<face>(0));
1716  List<DynamicList<label>> patchOwners(nPatches, DynamicList<label>(0));
1717  // Per patch face the index of the slave node of the point pair
1718  List<DynamicList<label>> patchPPSlaves(nPatches, DynamicList<label>(0));
1719 
1720  List<DynamicList<bool>> indirectPatchFace(nPatches, DynamicList<bool>(0));
1721 
1722 
1723  faces.setSize(number_of_finite_edges());
1724  owner.setSize(number_of_finite_edges());
1725  neighbour.setSize(number_of_finite_edges());
1726  boundaryFacesToRemove.setSize(number_of_finite_edges(), false);
1727 
1728  labelPairPairDynListList procPatchSortingIndex(nPatches);
1729 
1730  label dualFacei = 0;
1731 
1732  if (foamyHexMeshControls().guardFeaturePoints())
1733  {
1734  OBJstream startCellStr("startingCell.obj");
1735  OBJstream featurePointFacesStr("ftPtFaces.obj");
1736  OBJstream featurePointDualsStr("ftPtDuals.obj");
1737  OFstream cellStr("vertexCells.obj");
1738 
1739  label vcount = 1;
1740 
1741  for
1742  (
1743  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1744  vit != finite_vertices_end();
1745  ++vit
1746  )
1747  {
1748  if (vit->constrained())
1749  {
1750  // Find a starting cell
1751  std::list<Cell_handle> vertexCells;
1752  finite_incident_cells(vit, std::back_inserter(vertexCells));
1753 
1754  Cell_handle startCell;
1755 
1756  for
1757  (
1758  std::list<Cell_handle>::iterator vcit = vertexCells.begin();
1759  vcit != vertexCells.end();
1760  ++vcit
1761  )
1762  {
1763  if ((*vcit)->featurePointExternalCell())
1764  {
1765  startCell = *vcit;
1766  }
1767 
1768  if ((*vcit)->real())
1769  {
1770  featurePointDualsStr.write
1771  (
1772  linePointRef(topoint(vit->point()), (*vcit)->dual())
1773  );
1774  }
1775  }
1776 
1777  // Error if startCell is null
1778  if (startCell == nullptr)
1779  {
1780  Pout<< "Start cell is null!" << endl;
1781  }
1782 
1783  // Need to pick a direction to walk in
1784  Cell_handle vc1 = startCell;
1785  Cell_handle vc2;
1786 
1787  Info<< "c1 index = " << vc1->cellIndex() << " "
1788  << vc1->dual() << endl;
1789 
1790  for (label cI = 0; cI < 4; ++cI)
1791  {
1792  Info<< "c1 = " << cI << " "
1793  << vc1->neighbor(cI)->cellIndex() << " v = "
1794  << vc1->neighbor(cI)->dual() << endl;
1795 
1796  Info<< vc1->vertex(cI)->info();
1797  }
1798 
1799  Cell_handle nextCell;
1800 
1801  for (label cI = 0; cI < 4; ++cI)
1802  {
1803  if (vc1->vertex(cI)->externalBoundaryPoint())
1804  {
1805  vc2 = vc1->neighbor(cI);
1806 
1807  Info<< " c2 is neighbor "
1808  << vc2->cellIndex()
1809  << " of c1" << endl;
1810 
1811  for (label cI = 0; cI < 4; ++cI)
1812  {
1813  Info<< " c2 = " << cI << " "
1814  << vc2->neighbor(cI)->cellIndex() << " v = "
1815  << vc2->vertex(cI)->index() << endl;
1816  }
1817 
1818  face f(3);
1819  f[0] = vit->index();
1820  f[1] = vc1->cellIndex();
1821  f[2] = vc2->cellIndex();
1822 
1823  Info<< "f " << f << endl;
1824  forAll(f, pI)
1825  {
1826  Info<< " " << pts[f[pI]] << endl;
1827  }
1828 
1829  vector correctNormal = calcSharedPatchNormal(vc1, vc2);
1830  correctNormal.normalise();
1831 
1832  Info<< " cN " << correctNormal << endl;
1833 
1834  vector fN = f.areaNormal(pts);
1835 
1836  if (mag(fN) < SMALL)
1837  {
1838  nextCell = vc2;
1839  continue;
1840  }
1841 
1842  fN.normalise();
1843  Info<< " fN " << fN << endl;
1844 
1845  if ((fN & correctNormal) > 0)
1846  {
1847  nextCell = vc2;
1848  break;
1849  }
1850  }
1851  }
1852 
1853  vc2 = nextCell;
1854 
1855  label own = vit->index();
1856  face f(3);
1857  f[0] = own;
1858 
1859  Info<< "Start walk from " << vc1->cellIndex()
1860  << " to " << vc2->cellIndex() << endl;
1861 
1862  // Walk while not at start cell
1863 
1864  label iter = 0;
1865  do
1866  {
1867  Info<< " Walk from " << vc1->cellIndex()
1868  << " " << vc1->dual()
1869  << " to " << vc2->cellIndex()
1870  << " " << vc2->dual()
1871  << endl;
1872 
1873  startCellStr.write(linePointRef(vc1->dual(), vc2->dual()));
1874 
1875  // Get patch by getting face between cells and the two
1876  // points on the face that are not the feature vertex
1877  label patchIndex =
1878  geometryToConformTo_.findPatch
1879  (
1880  topoint(vit->point())
1881  );
1882 
1883  f[1] = vc1->cellIndex();
1884  f[2] = vc2->cellIndex();
1885 
1886  patchFaces[patchIndex].append(f);
1887  patchOwners[patchIndex].append(own);
1888  patchPPSlaves[patchIndex].append(own);
1889 
1890  // Find next cell
1891  Cell_handle nextCell;
1892 
1893  Info<< " c1 vertices " << vc2->dual() << endl;
1894  for (label cI = 0; cI < 4; ++cI)
1895  {
1896  Info<< " " << vc2->vertex(cI)->info();
1897  }
1898  Info<< " c1 neighbour vertices " << endl;
1899  for (label cI = 0; cI < 4; ++cI)
1900  {
1901  if
1902  (
1903  !vc2->vertex(cI)->constrained()
1904  && vc2->neighbor(cI) != vc1
1905  && !is_infinite(vc2->neighbor(cI))
1906  &&
1907  (
1908  vc2->neighbor(cI)->featurePointExternalCell()
1909  || vc2->neighbor(cI)->featurePointInternalCell()
1910  )
1911  && vc2->neighbor(cI)->hasConstrainedPoint()
1912  )
1913  {
1915  (
1916  cellStr,
1917  vc2->neighbor(cI),
1918  vcount++
1919  );
1920 
1921  Info<< " neighbour " << cI << " "
1922  << vc2->neighbor(cI)->dual() << endl;
1923  for (label I = 0; I < 4; ++I)
1924  {
1925  Info<< " "
1926  << vc2->neighbor(cI)->vertex(I)->info();
1927  }
1928  }
1929  }
1930 
1931  for (label cI = 0; cI < 4; ++cI)
1932  {
1933  if
1934  (
1935  !vc2->vertex(cI)->constrained()
1936  && vc2->neighbor(cI) != vc1
1937  && !is_infinite(vc2->neighbor(cI))
1938  &&
1939  (
1940  vc2->neighbor(cI)->featurePointExternalCell()
1941  || vc2->neighbor(cI)->featurePointInternalCell()
1942  )
1943  && vc2->neighbor(cI)->hasConstrainedPoint()
1944  )
1945  {
1946  // check if shared edge is internal/internal
1947  if (boundaryDualFace(vc2, vc2->neighbor(cI)))
1948  {
1949  nextCell = vc2->neighbor(cI);
1950  break;
1951  }
1952  }
1953  }
1954 
1955  vc1 = vc2;
1956  vc2 = nextCell;
1957 
1958  iter++;
1959  } while (vc1 != startCell && iter < 100);
1960  }
1961  }
1962  }
1963 
1964  for
1965  (
1966  Delaunay::Finite_edges_iterator eit = finite_edges_begin();
1967  eit != finite_edges_end();
1968  ++eit
1969  )
1970  {
1971  Cell_handle c = eit->first;
1972  Vertex_handle vA = c->vertex(eit->second);
1973  Vertex_handle vB = c->vertex(eit->third);
1974 
1975  if (vA->constrained() && vB->constrained())
1976  {
1977  continue;
1978  }
1979 
1980  if
1981  (
1982  (vA->constrained() && vB->internalOrBoundaryPoint())
1983  || (vB->constrained() && vA->internalOrBoundaryPoint())
1984  )
1985  {
1986  face newDualFace = buildDualFace(eit);
1987 
1988  label own = -1;
1989  label nei = -1;
1990 
1991  if (ownerAndNeighbour(vA, vB, own, nei))
1992  {
1993  reverse(newDualFace);
1994  }
1995 
1996  // internal face
1997  faces[dualFacei] = newDualFace;
1998  owner[dualFacei] = own;
1999  neighbour[dualFacei] = nei;
2000 
2001  dualFacei++;
2002  }
2003  else if
2004  (
2005  (vA->internalOrBoundaryPoint() && !vA->referred())
2006  || (vB->internalOrBoundaryPoint() && !vB->referred())
2007  )
2008  {
2009  if
2010  (
2011  (vA->internalPoint() && vB->externalBoundaryPoint())
2012  || (vB->internalPoint() && vA->externalBoundaryPoint())
2013  )
2014  {
2015  Cell_circulator ccStart = incident_cells(*eit);
2016  Cell_circulator cc1 = ccStart;
2017  Cell_circulator cc2 = cc1;
2018 
2019  cc2++;
2020 
2021  bool skipEdge = false;
2022 
2023  do
2024  {
2025  if
2026  (
2027  cc1->hasFarPoint() || cc2->hasFarPoint()
2028  || is_infinite(cc1) || is_infinite(cc2)
2029  )
2030  {
2031  Pout<< "Ignoring edge between internal and external: "
2032  << vA->info()
2033  << vB->info();
2034 
2035  skipEdge = true;
2036  break;
2037  }
2038 
2039  cc1++;
2040  cc2++;
2041 
2042  } while (cc1 != ccStart);
2043 
2044 
2045  // Do not create faces if the internal point is outside!
2046  // This occurs because the internal point is not determined to
2047  // be outside in the inside/outside test. This is most likely
2048  // due to the triangle.nearestPointClassify test not returning
2049  // edge/point as the nearest type.
2050 
2051  if (skipEdge)
2052  {
2053  continue;
2054  }
2055  }
2056 
2057  face newDualFace = buildDualFace(eit);
2058 
2059  if (newDualFace.size() >= 3)
2060  {
2061  label own = -1;
2062  label nei = -1;
2063 
2064  if (ownerAndNeighbour(vA, vB, own, nei))
2065  {
2066  reverse(newDualFace);
2067  }
2068 
2069  label patchIndex = -1;
2070 
2071  pointFromPoint ptA = topoint(vA->point());
2072  pointFromPoint ptB = topoint(vB->point());
2073 
2074  if (nei == -1)
2075  {
2076  // boundary face
2077 
2078  if (isProcBoundaryEdge(eit))
2079  {
2080  // One (and only one) of the points is an internal
2081  // point from another processor
2082 
2083  label procIndex = max(vA->procIndex(), vB->procIndex());
2084 
2085  patchIndex = max
2086  (
2087  procNeighbours.find(vA->procIndex()),
2088  procNeighbours.find(vB->procIndex())
2089  );
2090 
2091  // The lower processor index is the owner of the
2092  // two for the purpose of sorting the patch faces.
2093 
2094  if (Pstream::myProcNo() < procIndex)
2095  {
2096  // Use this processor's vertex index as the master
2097  // for sorting
2098 
2099  DynamicList<labelPairPair>& sortingIndex =
2100  procPatchSortingIndex[patchIndex];
2101 
2102  if (vB->internalOrBoundaryPoint() && vB->referred())
2103  {
2104  sortingIndex.append
2105  (
2107  (
2108  labelPair(vA->index(), vA->procIndex()),
2109  labelPair(vB->index(), vB->procIndex())
2110  )
2111  );
2112  }
2113  else
2114  {
2115  sortingIndex.append
2116  (
2118  (
2119  labelPair(vB->index(), vB->procIndex()),
2120  labelPair(vA->index(), vA->procIndex())
2121  )
2122  );
2123  }
2124  }
2125  else
2126  {
2127  // Use the other processor's vertex index as the
2128  // master for sorting
2129 
2130  DynamicList<labelPairPair>& sortingIndex =
2131  procPatchSortingIndex[patchIndex];
2132 
2133  if (vA->internalOrBoundaryPoint() && vA->referred())
2134  {
2135  sortingIndex.append
2136  (
2138  (
2139  labelPair(vA->index(), vA->procIndex()),
2140  labelPair(vB->index(), vB->procIndex())
2141  )
2142  );
2143  }
2144  else
2145  {
2146  sortingIndex.append
2147  (
2149  (
2150  labelPair(vB->index(), vB->procIndex()),
2151  labelPair(vA->index(), vA->procIndex())
2152  )
2153  );
2154  }
2155  }
2156 
2157 // Pout<< ptA << " " << ptB
2158 // << " proc indices "
2159 // << vA->procIndex() << " " << vB->procIndex()
2160 // << " indices " << vA->index()
2161 // << " " << vB->index()
2162 // << " my proc " << Pstream::myProcNo()
2163 // << " addedIndex "
2164 // << procPatchSortingIndex[patchIndex].last()
2165 // << endl;
2166  }
2167  else
2168  {
2169  patchIndex = geometryToConformTo_.findPatch(ptA, ptB);
2170  }
2171 
2172  if (patchIndex == -1)
2173  {
2174  // Did not find a surface patch between
2175  // between Dv pair, finding nearest patch
2176 
2177 // Pout<< "Did not find a surface patch between "
2178 // << "for face, finding nearest patch to"
2179 // << 0.5*(ptA + ptB) << endl;
2180 
2181  patchIndex = geometryToConformTo_.findPatch
2182  (
2183  0.5*(ptA + ptB)
2184  );
2185  }
2186 
2187  patchFaces[patchIndex].append(newDualFace);
2188  patchOwners[patchIndex].append(own);
2189 
2190  // If the two vertices are a pair, then the patch face is
2191  // a desired one.
2192  if
2193  (
2194  vA->boundaryPoint() && vB->boundaryPoint()
2195  && !ptPairs_.isPointPair(vA, vB)
2196  && !ftPtConformer_.featurePointPairs().isPointPair(vA, vB)
2197  )
2198  {
2199  indirectPatchFace[patchIndex].append(true);
2200  }
2201  else
2202  {
2203  indirectPatchFace[patchIndex].append(false);
2204  }
2205 
2206  // Store the non-internal or boundary point
2207  if (vA->internalOrBoundaryPoint())
2208  {
2209  patchPPSlaves[patchIndex].append(vB->index());
2210  }
2211  else
2212  {
2213  patchPPSlaves[patchIndex].append(vA->index());
2214  }
2215  }
2216  else
2217  {
2218  if
2219  (
2220  !vA->boundaryPoint()
2221  || !vB->boundaryPoint()
2222  || ptPairs_.isPointPair(vA, vB)
2223  || ftPtConformer_.featurePointPairs().isPointPair(vA, vB)
2224  )
2225  {
2226  patchIndex = geometryToConformTo_.findPatch(ptA, ptB);
2227  }
2228 
2229  if
2230  (
2231  patchIndex != -1
2232  && geometryToConformTo_.patchInfo().set(patchIndex)
2233  )
2234  {
2235  // baffle faces
2236 
2237  patchFaces[patchIndex].append(newDualFace);
2238  patchOwners[patchIndex].append(own);
2239  indirectPatchFace[patchIndex].append(false);
2240 
2241  reverse(newDualFace);
2242 
2243  patchFaces[patchIndex].append(newDualFace);
2244  patchOwners[patchIndex].append(nei);
2245  indirectPatchFace[patchIndex].append(false);
2246 
2247  if
2248  (
2249  labelPair(vB->index(), vB->procIndex())
2250  < labelPair(vA->index(), vA->procIndex())
2251  )
2252  {
2253  patchPPSlaves[patchIndex].append(vB->index());
2254  patchPPSlaves[patchIndex].append(vB->index());
2255  }
2256  else
2257  {
2258  patchPPSlaves[patchIndex].append(vA->index());
2259  patchPPSlaves[patchIndex].append(vA->index());
2260  }
2261 
2262  }
2263  else
2264  {
2265  // internal face
2266  faces[dualFacei] = newDualFace;
2267  owner[dualFacei] = own;
2268  neighbour[dualFacei] = nei;
2269 
2270  dualFacei++;
2271  }
2272  }
2273  }
2274  }
2275  }
2276 
2277  if (!patchFaces[defaultPatchIndex].empty())
2278  {
2279  Pout<< nl << patchFaces[defaultPatchIndex].size()
2280  << " faces were not able to have their patch determined from "
2281  << "the surface. "
2282  << nl << "Adding to patch " << patchNames[defaultPatchIndex]
2283  << endl;
2284  }
2285 
2286  label nInternalFaces = dualFacei;
2287 
2288  faces.setSize(nInternalFaces);
2289  owner.setSize(nInternalFaces);
2290  neighbour.setSize(nInternalFaces);
2291 
2292  timeCheck("polyMesh quality checked");
2293 
2294  sortFaces(faces, owner, neighbour);
2295 
2296  sortProcPatches
2297  (
2298  patchFaces,
2299  patchOwners,
2300  patchPPSlaves,
2301  procPatchSortingIndex
2302  );
2303 
2304  timeCheck("faces, owner, neighbour sorted");
2305 
2306  addPatches
2307  (
2308  nInternalFaces,
2309  faces,
2310  owner,
2311  patchDicts,
2312  boundaryFacesToRemove,
2313  patchFaces,
2314  patchOwners,
2315  indirectPatchFace
2316  );
2317 
2318  // Return patchPointPairSlaves.setSize(nPatches);
2319  patchPointPairSlaves.setSize(nPatches);
2320  forAll(patchPPSlaves, patchi)
2321  {
2322  patchPointPairSlaves[patchi].transfer(patchPPSlaves[patchi]);
2323  }
2324 
2325  if (foamyHexMeshControls().objOutput())
2326  {
2327  Info<< "Writing processor interfaces" << endl;
2328 
2329  forAll(patchDicts, nbI)
2330  {
2331  if (patchFaces[nbI].size() > 0)
2332  {
2333  const label neighbour =
2334  patchDicts[nbI].getOrDefault<label>("neighbProcNo", -1);
2335 
2336  faceList procPatchFaces = patchFaces[nbI];
2337 
2338  // Reverse faces as it makes it easier to analyse the output
2339  // using a diff
2340  if (neighbour < Pstream::myProcNo())
2341  {
2342  forAll(procPatchFaces, fI)
2343  {
2344  procPatchFaces[fI].flip();
2345  }
2346  }
2347 
2348  if (neighbour != -1)
2349  {
2350  word fName =
2351  "processor_"
2352  + name(Pstream::myProcNo())
2353  + "_to_"
2354  + name(neighbour)
2355  + "_interface.obj";
2356 
2358  (
2359  time().path()/fName,
2360  *this,
2361  procPatchFaces
2362  );
2363  }
2364  }
2365  }
2366  }
2367 }
2368 
2369 
2370 void Foam::conformalVoronoiMesh::sortFaces
2371 (
2372  faceList& faces,
2373  labelList& owner,
2374  labelList& neighbour
2375 ) const
2376 {
2377  // Upper triangular order:
2378  // + owner is sorted in ascending cell order
2379  // + within each block of equal value for owner, neighbour is sorted in
2380  // ascending cell order.
2381  // + faces sorted to correspond
2382  // e.g.
2383  // owner | neighbour
2384  // 0 | 2
2385  // 0 | 23
2386  // 0 | 71
2387  // 1 | 23
2388  // 1 | 24
2389  // 1 | 91
2390 
2391  List<labelPair> ownerNeighbourPair(owner.size());
2392 
2393  forAll(ownerNeighbourPair, oNI)
2394  {
2395  ownerNeighbourPair[oNI] = labelPair(owner[oNI], neighbour[oNI]);
2396  }
2397 
2398  Info<< nl
2399  << "Sorting faces, owner and neighbour into upper triangular order"
2400  << endl;
2401 
2402  labelList oldToNew(sortedOrder(ownerNeighbourPair));
2403  oldToNew = invert(oldToNew.size(), oldToNew);
2404 
2405  inplaceReorder(oldToNew, faces);
2406  inplaceReorder(oldToNew, owner);
2407  inplaceReorder(oldToNew, neighbour);
2408 }
2409 
2410 
2411 void Foam::conformalVoronoiMesh::sortProcPatches
2412 (
2413  List<DynamicList<face>>& patchFaces,
2414  List<DynamicList<label>>& patchOwners,
2415  List<DynamicList<label>>& patchPointPairSlaves,
2416  labelPairPairDynListList& patchSortingIndices
2417 ) const
2418 {
2419  if (!Pstream::parRun())
2420  {
2421  return;
2422  }
2423 
2424  forAll(patchSortingIndices, patchi)
2425  {
2426  faceList& faces = patchFaces[patchi];
2427  labelList& owner = patchOwners[patchi];
2428  DynamicList<label>& slaves = patchPointPairSlaves[patchi];
2429  DynamicList<labelPairPair>& sortingIndices
2430  = patchSortingIndices[patchi];
2431 
2432  if (!sortingIndices.empty())
2433  {
2434  if
2435  (
2436  faces.size() != sortingIndices.size()
2437  || owner.size() != sortingIndices.size()
2438  || slaves.size() != sortingIndices.size()
2439  )
2440  {
2442  << "patch size and size of sorting indices is inconsistent "
2443  << " for patch " << patchi << nl
2444  << " faces.size() " << faces.size() << nl
2445  << " owner.size() " << owner.size() << nl
2446  << " slaves.size() " << slaves.size() << nl
2447  << " sortingIndices.size() "
2448  << sortingIndices.size()
2449  << exit(FatalError) << endl;
2450  }
2451 
2452  labelList oldToNew(sortedOrder(sortingIndices));
2453  oldToNew = invert(oldToNew.size(), oldToNew);
2454 
2455  inplaceReorder(oldToNew, sortingIndices);
2456  inplaceReorder(oldToNew, faces);
2457  inplaceReorder(oldToNew, owner);
2458  inplaceReorder(oldToNew, slaves);
2459  }
2460  }
2461 }
2462 
2463 
2464 void Foam::conformalVoronoiMesh::addPatches
2465 (
2466  const label nInternalFaces,
2467  faceList& faces,
2468  labelList& owner,
2469  PtrList<dictionary>& patchDicts,
2470  bitSet& boundaryFacesToRemove,
2471  const List<DynamicList<face>>& patchFaces,
2472  const List<DynamicList<label>>& patchOwners,
2473  const List<DynamicList<bool>>& indirectPatchFace
2474 ) const
2475 {
2476  label nBoundaryFaces = 0;
2477 
2478  forAll(patchFaces, p)
2479  {
2480  patchDicts[p].set("nFaces", patchFaces[p].size());
2481  patchDicts[p].set("startFace", nInternalFaces + nBoundaryFaces);
2482 
2483  nBoundaryFaces += patchFaces[p].size();
2484  }
2485 
2486  faces.setSize(nInternalFaces + nBoundaryFaces);
2487  owner.setSize(nInternalFaces + nBoundaryFaces);
2488  boundaryFacesToRemove.setSize(nInternalFaces + nBoundaryFaces);
2489 
2490  label facei = nInternalFaces;
2491 
2492  forAll(patchFaces, p)
2493  {
2494  forAll(patchFaces[p], f)
2495  {
2496  faces[facei] = patchFaces[p][f];
2497  owner[facei] = patchOwners[p][f];
2498  boundaryFacesToRemove[facei] = indirectPatchFace[p][f];
2499 
2500  facei++;
2501  }
2502  }
2503 }
2504 
2505 
2506 void Foam::conformalVoronoiMesh::removeUnusedPoints
2507 (
2508  faceList& faces,
2509  pointField& pts,
2510  labelList& boundaryPts
2511 ) const
2512 {
2513  Info<< nl << "Removing unused points" << endl;
2514 
2515  bitSet ptUsed(pts.size(), false);
2516 
2517  // Scan all faces to find all of the points that are used
2518 
2519  forAll(faces, fI)
2520  {
2521  const face& f = faces[fI];
2522 
2523  ptUsed.set(f);
2524  }
2525 
2526  label pointi = 0;
2527 
2528  labelList oldToNew(pts.size(), label(-1));
2529 
2530  // Move all of the used points to the start of the pointField and
2531  // truncate it
2532 
2533  forAll(ptUsed, ptUI)
2534  {
2535  if (ptUsed.test(ptUI))
2536  {
2537  oldToNew[ptUI] = pointi++;
2538  }
2539  }
2540 
2541  inplaceReorder(oldToNew, pts);
2542  inplaceReorder(oldToNew, boundaryPts);
2543 
2544  Info<< " Removing "
2545  << returnReduce(pts.size() - pointi, sumOp<label>())
2546  << " unused points"
2547  << endl;
2548 
2549  pts.setSize(pointi);
2550  boundaryPts.setSize(pointi);
2551 
2552  // Renumber the faces to use the new point numbers
2553 
2554  forAll(faces, fI)
2555  {
2556  inplaceRenumber(oldToNew, faces[fI]);
2557  }
2558 }
2559 
2560 
2561 Foam::labelList Foam::conformalVoronoiMesh::removeUnusedCells
2562 (
2563  labelList& owner,
2564  labelList& neighbour
2565 ) const
2566 {
2567  Info<< nl << "Removing unused cells" << endl;
2568 
2569  bitSet cellUsed(vertexCount(), false);
2570 
2571  // Scan all faces to find all of the cells that are used
2572 
2573  cellUsed.set(owner);
2574  cellUsed.set(neighbour);
2575 
2576  label celli = 0;
2577 
2578  labelList oldToNew(cellUsed.size(), label(-1));
2579 
2580  // Move all of the used cellCentres to the start of the pointField and
2581  // truncate it
2582 
2583  forAll(cellUsed, cellUI)
2584  {
2585  if (cellUsed.test(cellUI))
2586  {
2587  oldToNew[cellUI] = celli++;
2588  }
2589  }
2590 
2591  labelList newToOld(invert(celli, oldToNew));
2592 
2593  // Find all of the unused cells, create a list of them, then
2594  // subtract one from each owner and neighbour entry for each of
2595  // the unused cell indices that it is above.
2596 
2597  DynamicList<label> unusedCells;
2598 
2599  forAll(cellUsed, cUI)
2600  {
2601  if (!cellUsed.test(cUI))
2602  {
2603  unusedCells.append(cUI);
2604  }
2605  }
2606 
2607  if (unusedCells.size() > 0)
2608  {
2609  Info<< " Removing "
2610  << returnReduce(unusedCells.size(), sumOp<label>())
2611  << " unused cell labels" << endl;
2612 
2613  forAll(owner, oI)
2614  {
2615  label& o = owner[oI];
2616 
2617  o -= findLower(unusedCells, o) + 1;
2618  }
2619 
2620  forAll(neighbour, nI)
2621  {
2622  label& n = neighbour[nI];
2623 
2624  n -= findLower(unusedCells, n) + 1;
2625  }
2626  }
2627 
2628  return newToOld;
2629 }
2630 
2631 
2632 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:195
Foam::autoPtr::New
static autoPtr< T > New(Args &&... args)
Construct autoPtr of T with forwarding arguments.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::polyMeshGeometry::checkFaceDotProduct
static bool checkFaceDotProduct(const bool report, const scalar orthWarn, const polyMesh &, const vectorField &cellCentres, const vectorField &faceAreas, const labelList &checkFaces, const List< labelPair > &baffles, labelHashSet *setPtr)
See primitiveMesh.
Definition: polyMeshGeometry.C:360
Foam::reverse
void reverse(UList< T > &list, const label n)
Definition: UListI.H:449
meshPtr
Foam::autoPtr< Foam::fvMesh > meshPtr(nullptr)
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
polyMeshGeometry.H
Foam::Pstream::scatterList
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
Definition: gatherScatterList.C:215
Foam::conformalVoronoiMesh::timeCheck
static void timeCheck(const Time &runTime, const string &description=string::null, const bool check=true)
Write the elapsedCpuTime and memory usage, with an optional.
motionSmoother.H
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:65
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:444
Foam::motionSmootherAlgo::checkMesh
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
Definition: motionSmootherAlgoCheck.C:462
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::dictionary::get
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:107
Foam::labelPairPair
Pair< labelPair > labelPairPair
A pair of labelPairs.
Definition: labelPair.H:63
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::HashSet< label, Hash< label > >
Foam::DelaunayMeshTools::drawDelaunayCell
void drawDelaunayCell(Ostream &os, const CellHandle &c, label offset=0)
Draws a tet cell to an output stream. The offset is supplied as the tet.
Foam::invert
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:36
nProcPatches
const label nProcPatches
Definition: convertProcessorPatches.H:171
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::topoint
pointFromPoint topoint(const Point &P)
Definition: pointConversion.H:72
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
patchDicts
PtrList< dictionary > patchDicts
Definition: readKivaGrid.H:532
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::wordList
List< word > wordList
A List of words.
Definition: fileName.H:62
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::primitiveMesh::nCells
label nCells() const noexcept
Number of mesh cells.
Definition: primitiveMeshI.H:96
nPatches
const label nPatches
Definition: printMeshSummary.H:30
backgroundMeshDecomposition.H
Foam::constant::physicoChemical::c1
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
Foam::findLower
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::polyBoundaryMesh::faceCells
UPtrList< const labelUList > faceCells() const
Return a list of faceCells for each patch.
Definition: polyBoundaryMesh.C:311
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::dictionary::subDict
const dictionary & subDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary.
Definition: dictionary.C:460
Foam::cellList
List< cell > cellList
A List of cells.
Definition: cellListFwd.H:47
Foam::PtrList::setSize
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:151
Foam::IOstream::info
InfoProxy< IOstream > info() const
Return info proxy.
Definition: IOstream.H:413
patchNames
wordList patchNames(nPatches)
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::polyPatch::New
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:35
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::Ostream::write
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
DelaunayMeshTools.H
Foam::DelaunayMeshTools::writeProcessorInterface
void writeProcessorInterface(const fileName &fName, const Triangulation &t, const faceList &faces)
Write the processor interface to an OBJ file.
Foam::constant::physicoChemical::c2
const dimensionedScalar c2
Second radiation constant: default SI units: [m.K].
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::autoPtr< Foam::polyMesh >
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::linePointRef
line< point, const point & > linePointRef
A line using referred points.
Definition: linePointRef.H:47
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::pointIndexHit
PointIndexHit< point > pointIndexHit
A PointIndexHit for 3D points.
Definition: pointIndexHit.H:46
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::VectorSpace< Vector< Cmpt >, Cmpt, 3 >::max
static const Vector< Cmpt > max
Definition: VectorSpace.H:117
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::Vector
Templated 3D Vector derived from VectorSpace adding construction from 3 components,...
Definition: Vector.H:62
Foam::UPstream::parRun
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
Foam::labelPairHashSet
HashSet< labelPair, Foam::Hash< labelPair > > labelPairHashSet
A HashSet for a labelPair. The hashing is based on labelPair (FixedList) and is thus non-commutative.
Definition: labelPairHashes.H:65
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::processorPolyPatch::newName
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
Definition: processorPolyPatch.C:185
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::identity
labelList identity(const label len, label start=0)
Create identity map of the given length with (map[i] == i)
Definition: labelList.C:38
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
path
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::List::set
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:341
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::inplaceReorder
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
Definition: ListOpsTemplates.C:124
Foam::DelaunayMeshTools::allPoints
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
ListOps.H
Various functions to operate on Lists.
Foam::sortedOrder
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
coupled
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:85
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
indexedCellOps.H
Foam::IOobject::NO_READ
Definition: IOobject.H:188
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
OBJstream.H
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::I
static const Identity< scalar > I
Definition: Identity.H:95
conformalVoronoiMesh.H
indexedCellChecks.H
Foam::keyType::REGEX_RECURSIVE
Definition: keyType.H:87