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-2020 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  if (!cellsToResizeMap.found(faceOwner))
898  {
899  cellsToResizeMap.insert(faceOwner);
900  }
901 
902  if (!cellsToResizeMap.found(faceNeighbour))
903  {
904  cellsToResizeMap.insert(faceNeighbour);
905  }
906  }
907 
908  cellsToResizeMap += protrudingCells;
909 
910  pointField cellsToResize(cellsToResizeMap.size());
911 
912  label count = 0;
913  for (label celli = 0; celli < pMesh.nCells(); ++celli)
914  {
915  if (cellsToResizeMap.found(celli))
916  {
917  cellsToResize[count++] = pMesh.cellCentres()[celli];
918  }
919  }
920 
921  Info<< " DISABLED: Automatically re-sizing " << cellsToResize.size()
922  << " cells that are attached to the bad faces: " << endl;
923 
924  //cellSizeControl_.setCellSizes(cellsToResize);
925  }
926 
927  timeCheck("End of Cell Sizing");
928 
929  Info<< "Finished checking cell sizes"<< endl;
930 }
931 
932 
933 Foam::labelHashSet Foam::conformalVoronoiMesh::findOffsetPatchFaces
934 (
935  const polyMesh& mesh,
936  const scalar allowedOffset
937 ) const
938 {
939  timeCheck("Start findRemainingProtrusionSet");
940 
941  const polyBoundaryMesh& patches = mesh.boundaryMesh();
942 
943  cellSet offsetBoundaryCells
944  (
945  mesh,
946  "foamyHexMesh_protrudingCells",
947  mesh.nCells()/1000
948  );
949 
950  forAll(patches, patchi)
951  {
952  const polyPatch& patch = patches[patchi];
953 
954  const faceList& localFaces = patch.localFaces();
955  const pointField& localPoints = patch.localPoints();
956 
957  const labelList& fCell = patch.faceCells();
958 
959  forAll(localFaces, pLFI)
960  {
961  const face& f = localFaces[pLFI];
962 
963  const Foam::point& faceCentre = f.centre(localPoints);
964 
965  const scalar targetSize = targetCellSize(faceCentre);
966 
967  pointIndexHit pHit;
968  label surfHit = -1;
969 
970  geometryToConformTo_.findSurfaceNearest
971  (
972  faceCentre,
973  sqr(targetSize),
974  pHit,
975  surfHit
976  );
977 
978  if
979  (
980  pHit.hit()
981  && (mag(pHit.hitPoint() - faceCentre) > allowedOffset*targetSize)
982  )
983  {
984  offsetBoundaryCells.insert(fCell[pLFI]);
985  }
986  }
987  }
988 
989  if (foamyHexMeshControls().objOutput())
990  {
991  offsetBoundaryCells.write();
992  }
993 
994  return std::move(offsetBoundaryCells);
995 }
996 
997 
998 Foam::labelHashSet Foam::conformalVoronoiMesh::checkPolyMeshQuality
999 (
1000  const pointField& pts
1001 ) const
1002 {
1003  autoPtr<polyMesh> meshPtr = createPolyMeshFromPoints(pts);
1004  polyMesh& pMesh = meshPtr();
1005 
1006  timeCheck("polyMesh created, checking quality");
1007 
1008  labelHashSet wrongFaces(pMesh.nFaces()/100);
1009 
1010  DynamicList<label> checkFaces(pMesh.nFaces());
1011 
1012  const vectorField& fAreas = pMesh.faceAreas();
1013 
1014  scalar faceAreaLimit = SMALL;
1015 
1016  forAll(fAreas, fI)
1017  {
1018  if (mag(fAreas[fI]) > faceAreaLimit)
1019  {
1020  checkFaces.append(fI);
1021  }
1022  }
1023 
1024  Info<< nl << "Excluding "
1025  << returnReduce(fAreas.size() - checkFaces.size(), sumOp<label>())
1026  << " faces from check, < " << faceAreaLimit << " area" << endl;
1027 
1028  const dictionary& dict
1029  = foamyHexMeshControls().foamyHexMeshDict();
1030 
1031  const dictionary& meshQualityDict
1032  = dict.subDict("meshQualityControls");
1033 
1035  (
1036  false,
1037  pMesh,
1038  meshQualityDict,
1039  checkFaces,
1040  wrongFaces
1041  );
1042 
1043  {
1044  // Check for cells with more than 1 but fewer than 4 faces
1045  label nInvalidPolyhedra = 0;
1046 
1047  const cellList& cells = pMesh.cells();
1048 
1049  forAll(cells, cI)
1050  {
1051  if (cells[cI].size() < 4 && cells[cI].size() > 0)
1052  {
1053  // Pout<< "cell " << cI << " " << cells[cI]
1054  // << " has " << cells[cI].size() << " faces."
1055  // << endl;
1056 
1057  nInvalidPolyhedra++;
1058 
1059  wrongFaces.insert(cells[cI]);
1060  }
1061  }
1062 
1063  Info<< " cells with more than 1 but fewer than 4 faces : "
1064  << returnReduce(nInvalidPolyhedra, sumOp<label>())
1065  << endl;
1066 
1067  // Check for cells with one internal face only
1068 
1069  labelList nInternalFaces(pMesh.nCells(), Zero);
1070 
1071  for (label fI = 0; fI < pMesh.nInternalFaces(); fI++)
1072  {
1073  nInternalFaces[pMesh.faceOwner()[fI]]++;
1074  nInternalFaces[pMesh.faceNeighbour()[fI]]++;
1075  }
1076 
1077  const polyBoundaryMesh& patches = pMesh.boundaryMesh();
1078 
1079  forAll(patches, patchi)
1080  {
1081  if (patches[patchi].coupled())
1082  {
1083  const labelUList& owners = patches[patchi].faceCells();
1084 
1085  forAll(owners, i)
1086  {
1087  nInternalFaces[owners[i]]++;
1088  }
1089  }
1090  }
1091 
1092  label oneInternalFaceCells = 0;
1093 
1094  forAll(nInternalFaces, cI)
1095  {
1096  if (nInternalFaces[cI] <= 1)
1097  {
1098  oneInternalFaceCells++;
1099  wrongFaces.insert(cells[cI]);
1100  }
1101  }
1102 
1103  Info<< " cells with with zero or one non-boundary face : "
1104  << returnReduce(oneInternalFaceCells, sumOp<label>())
1105  << endl;
1106  }
1107 
1108 
1109  bitSet ptToBeLimited(pts.size(), false);
1110 
1111  for (const label facei : wrongFaces)
1112  {
1113  const face f = pMesh.faces()[facei];
1114 
1115  ptToBeLimited.set(f);
1116  }
1117 
1118  // // Limit connected cells
1119 
1120  // labelHashSet limitCells(pMesh.nCells()/100);
1121 
1122  // const labelListList& ptCells = pMesh.pointCells();
1123 
1124  // for (const label facei : wrongFaces)
1125  // {
1126  // const face f = pMesh.faces()[facei];
1127 
1128  // forAll(f, fPtI)
1129  // {
1130  // label ptI = f[fPtI];
1131  // const labelList& pC = ptCells[ptI];
1132  // limitCells.insert(pC);
1133  // }
1134  // }
1135 
1136  // const labelListList& cellPts = pMesh.cellPoints();
1137 
1138  // for (const label celli : limitCells)
1139  // {
1140  // const labelList& cP = cellPts[celli];
1141 
1142  // ptToBeLimited.set(cP);
1143  // }
1144 
1145 
1146  // Apply Delaunay cell filterCounts and determine the maximum
1147  // overall filterCount
1148 
1149  label maxFilterCount = 0;
1150 
1151  for
1152  (
1153  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1154  cit != finite_cells_end();
1155  ++cit
1156  )
1157  {
1158  label cI = cit->cellIndex();
1159 
1160  if (cI >= 0)
1161  {
1162  if (ptToBeLimited.test(cI))
1163  {
1164  cit->filterCount()++;
1165  }
1166 
1167  if (cit->filterCount() > maxFilterCount)
1168  {
1169  maxFilterCount = cit->filterCount();
1170  }
1171  }
1172  }
1173 
1174  Info<< nl << "Maximum number of filter limits applied: "
1175  << returnReduce(maxFilterCount, maxOp<label>()) << endl;
1176 
1177  return wrongFaces;
1178 }
1179 
1180 
1181 Foam::label Foam::conformalVoronoiMesh::classifyBoundaryPoint
1182 (
1183  Cell_handle cit
1184 ) const
1185 {
1186  if (cit->boundaryDualVertex())
1187  {
1188  if (cit->featurePointDualVertex())
1189  {
1190  return featurePoint;
1191  }
1192  else if (cit->featureEdgeDualVertex())
1193  {
1194  return featureEdge;
1195  }
1196  else
1197  {
1198  return surface;
1199  }
1200  }
1201  else if (cit->baffleSurfaceDualVertex())
1202  {
1203  return surface;
1204  }
1205  else if (cit->baffleEdgeDualVertex())
1206  {
1207  return featureEdge;
1208  }
1209  else
1210  {
1211  return internal;
1212  }
1213 }
1214 
1215 
1216 void Foam::conformalVoronoiMesh::indexDualVertices
1217 (
1218  pointField& pts,
1219  labelList& boundaryPts
1220 )
1221 {
1222  // Indexing Delaunay cells, which are the dual vertices
1223 
1224  this->resetCellCount();
1225 
1226  label nConstrainedVertices = 0;
1227  if (foamyHexMeshControls().guardFeaturePoints())
1228  {
1229  for
1230  (
1231  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1232  vit != finite_vertices_end();
1233  ++vit
1234  )
1235  {
1236  if (vit->constrained())
1237  {
1238  vit->index() = number_of_finite_cells() + nConstrainedVertices;
1239  nConstrainedVertices++;
1240  }
1241  }
1242  }
1243 
1244  pts.setSize(number_of_finite_cells() + nConstrainedVertices);
1245  boundaryPts.setSize
1246  (
1247  number_of_finite_cells() + nConstrainedVertices,
1248  internal
1249  );
1250 
1251  if (foamyHexMeshControls().guardFeaturePoints())
1252  {
1253  nConstrainedVertices = 0;
1254  for
1255  (
1256  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1257  vit != finite_vertices_end();
1258  ++vit
1259  )
1260  {
1261  if (vit->constrained())
1262  {
1263  pts[number_of_finite_cells() + nConstrainedVertices] =
1264  topoint(vit->point());
1265 
1266  boundaryPts[number_of_finite_cells() + nConstrainedVertices] =
1267  constrained;
1268 
1269  nConstrainedVertices++;
1270  }
1271  }
1272  }
1273 
1274  //OBJstream snapping1("snapToSurface1.obj");
1275  //OBJstream snapping2("snapToSurface2.obj");
1276  //OFstream tetToSnapTo("tetsToSnapTo.obj");
1277 
1278  for
1279  (
1280  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1281  cit != finite_cells_end();
1282  ++cit
1283  )
1284  {
1285 // if (tetrahedron(cit).volume() == 0)
1286 // {
1287 // Pout<< "ZERO VOLUME TET" << endl;
1288 // Pout<< cit->info();
1289 // Pout<< "Dual = " << cit->dual();
1290 // }
1291 
1292  if (!cit->hasFarPoint())
1293  {
1294  cit->cellIndex() = getNewCellIndex();
1295 
1296  // For nearly coplanar Delaunay cells that are present on different
1297  // processors the result of the circumcentre calculation depends on
1298  // the ordering of the vertices, so synchronise it across processors
1299 
1300  if (Pstream::parRun() && cit->parallelDualVertex())
1301  {
1302  typedef CGAL::Exact_predicates_exact_constructions_kernel Exact;
1303  typedef CGAL::Point_3<Exact> ExactPoint;
1304 
1305  List<labelPair> cellVerticesPair(4);
1306  List<ExactPoint> cellVertices(4);
1307 
1308  for (label vI = 0; vI < 4; ++vI)
1309  {
1310  cellVerticesPair[vI] = labelPair
1311  (
1312  cit->vertex(vI)->procIndex(),
1313  cit->vertex(vI)->index()
1314  );
1315 
1316  cellVertices[vI] = ExactPoint
1317  (
1318  cit->vertex(vI)->point().x(),
1319  cit->vertex(vI)->point().y(),
1320  cit->vertex(vI)->point().z()
1321  );
1322  }
1323 
1324  // Sort the vertices so that they will be in the same order on
1325  // each processor
1326  labelList oldToNew(sortedOrder(cellVerticesPair));
1327  oldToNew = invert(oldToNew.size(), oldToNew);
1328  inplaceReorder(oldToNew, cellVertices);
1329 
1330  ExactPoint synchronisedDual = CGAL::circumcenter
1331  (
1332  cellVertices[0],
1333  cellVertices[1],
1334  cellVertices[2],
1335  cellVertices[3]
1336  );
1337 
1338  pts[cit->cellIndex()] = Foam::point
1339  (
1340  CGAL::to_double(synchronisedDual.x()),
1341  CGAL::to_double(synchronisedDual.y()),
1342  CGAL::to_double(synchronisedDual.z())
1343  );
1344  }
1345  else
1346  {
1347  pts[cit->cellIndex()] = cit->dual();
1348  }
1349 
1350  // Feature point snapping
1351  if (foamyHexMeshControls().snapFeaturePoints())
1352  {
1353  if (cit->featurePointDualVertex())
1354  {
1355  pointFromPoint dual = cit->dual();
1356 
1357  pointIndexHit fpHit;
1358  label featureHit;
1359 
1360  // Find nearest feature point and compare
1361  geometryToConformTo_.findFeaturePointNearest
1362  (
1363  dual,
1364  sqr(targetCellSize(dual)),
1365  fpHit,
1366  featureHit
1367  );
1368 
1369  if (fpHit.hit())
1370  {
1371  if (debug)
1372  {
1373  Info<< "Dual = " << dual << nl
1374  << " Nearest = " << fpHit.hitPoint() << endl;
1375  }
1376 
1377  pts[cit->cellIndex()] = fpHit.hitPoint();
1378  }
1379  }
1380  }
1381 
1382 // {
1383 // // Snapping points far outside
1384 // if (cit->boundaryDualVertex() && !cit->parallelDualVertex())
1385 // {
1386 // pointFromPoint dual = cit->dual();
1387 //
1388 // pointIndexHit hitInfo;
1389 // label surfHit;
1390 //
1391 // // Find nearest surface point
1392 // geometryToConformTo_.findSurfaceNearest
1393 // (
1394 // dual,
1395 // sqr(targetCellSize(dual)),
1396 // hitInfo,
1397 // surfHit
1398 // );
1399 //
1400 // if (!hitInfo.hit())
1401 // {
1402 // // Project dual to nearest point on tet
1403 //
1404 // tetPointRef tet
1405 // (
1406 // topoint(cit->vertex(0)->point()),
1407 // topoint(cit->vertex(1)->point()),
1408 // topoint(cit->vertex(2)->point()),
1409 // topoint(cit->vertex(3)->point())
1410 // );
1411 //
1412 // pointFromPoint nearestPointOnTet =
1413 // tet.nearestPoint(dual).rawPoint();
1414 //
1415 // // Get nearest point on surface from tet.
1416 // geometryToConformTo_.findSurfaceNearest
1417 // (
1418 // nearestPointOnTet,
1419 // sqr(targetCellSize(nearestPointOnTet)),
1420 // hitInfo,
1421 // surfHit
1422 // );
1423 //
1424 // vector snapDir = nearestPointOnTet - dual;
1425 // snapDir /= mag(snapDir) + SMALL;
1426 //
1427 // drawDelaunayCell(tetToSnapTo, cit, offset);
1428 // offset += 1;
1429 //
1430 // vectorField norm(1);
1431 // allGeometry_[surfHit].getNormal
1432 // (
1433 // List<pointIndexHit>(1, hitInfo),
1434 // norm
1435 // );
1436 // norm[0] /= mag(norm[0]) + SMALL;
1437 //
1438 // if
1439 // (
1440 // hitInfo.hit()
1441 // && (mag(snapDir & norm[0]) > 0.5)
1442 // )
1443 // {
1444 // snapping1.write
1445 // (
1446 // linePointRef(dual, nearestPointOnTet)
1447 // );
1448 //
1449 // snapping2.write
1450 // (
1451 // linePointRef
1452 // (
1453 // nearestPointOnTet,
1454 // hitInfo.hitPoint()
1455 // )
1456 // );
1457 //
1458 // pts[cit->cellIndex()] = hitInfo.hitPoint();
1459 // }
1460 // }
1461 // }
1462 // }
1463 
1464  boundaryPts[cit->cellIndex()] = classifyBoundaryPoint(cit);
1465  }
1466  else
1467  {
1468  cit->cellIndex() = Cb::ctFar;
1469  }
1470  }
1471 
1472  //pts.setSize(this->cellCount());
1473 
1474  //boundaryPts.setSize(this->cellCount());
1475 }
1476 
1477 
1478 void Foam::conformalVoronoiMesh::reindexDualVertices
1479 (
1480  const Map<label>& dualPtIndexMap,
1481  labelList& boundaryPts
1482 )
1483 {
1484  for
1485  (
1486  Delaunay::Finite_cells_iterator cit = finite_cells_begin();
1487  cit != finite_cells_end();
1488  ++cit
1489  )
1490  {
1491  if (dualPtIndexMap.found(cit->cellIndex()))
1492  {
1493  cit->cellIndex() = dualPtIndexMap[cit->cellIndex()];
1494  boundaryPts[cit->cellIndex()] =
1495  max
1496  (
1497  boundaryPts[cit->cellIndex()],
1498  boundaryPts[dualPtIndexMap[cit->cellIndex()]]
1499  );
1500  }
1501  }
1502 }
1503 
1504 
1505 Foam::label Foam::conformalVoronoiMesh::createPatchInfo
1506 (
1508  PtrList<dictionary>& patchDicts
1509 ) const
1510 {
1511  patchNames = geometryToConformTo_.patchNames();
1512 
1513  patchDicts.setSize(patchNames.size() + 1);
1514 
1515  const PtrList<dictionary>& patchInfo = geometryToConformTo_.patchInfo();
1516 
1517  forAll(patchNames, patchi)
1518  {
1519  if (patchInfo.set(patchi))
1520  {
1521  patchDicts.set(patchi, new dictionary(patchInfo[patchi]));
1522  }
1523  else
1524  {
1525  patchDicts.set(patchi, new dictionary());
1526  patchDicts[patchi].set
1527  (
1528  "type",
1529  wallPolyPatch::typeName
1530  );
1531  }
1532  }
1533 
1534  patchNames.setSize(patchNames.size() + 1);
1535  label defaultPatchIndex = patchNames.size() - 1;
1536  patchNames[defaultPatchIndex] = "foamyHexMesh_defaultPatch";
1537  patchDicts.set(defaultPatchIndex, new dictionary());
1538  patchDicts[defaultPatchIndex].set
1539  (
1540  "type",
1541  wallPolyPatch::typeName
1542  );
1543 
1544  label nProcPatches = 0;
1545 
1546  if (Pstream::parRun())
1547  {
1548  List<boolList> procUsedList
1549  (
1550  Pstream::nProcs(),
1551  boolList(Pstream::nProcs(), false)
1552  );
1553 
1554  boolList& procUsed = procUsedList[Pstream::myProcNo()];
1555 
1556  // Determine which processor patches are required
1557  for
1558  (
1559  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1560  vit != finite_vertices_end();
1561  vit++
1562  )
1563  {
1564  // This test is not sufficient if one of the processors does
1565  // not receive a referred vertex from another processor, but does
1566  // send one to the other processor.
1567  if (vit->referred())
1568  {
1569  procUsed[vit->procIndex()] = true;
1570  }
1571  }
1572 
1573  // Because the previous test was insufficient, combine the lists.
1574  Pstream::gatherList(procUsedList);
1575  Pstream::scatterList(procUsedList);
1576 
1577  forAll(procUsedList, proci)
1578  {
1579  if (proci != Pstream::myProcNo())
1580  {
1581  if (procUsedList[proci][Pstream::myProcNo()])
1582  {
1583  procUsed[proci] = true;
1584  }
1585  }
1586  }
1587 
1588  forAll(procUsed, pUI)
1589  {
1590  if (procUsed[pUI])
1591  {
1592  nProcPatches++;
1593  }
1594  }
1595 
1596  label nNonProcPatches = patchNames.size();
1597  label nTotalPatches = nNonProcPatches + nProcPatches;
1598 
1599  patchNames.setSize(nTotalPatches);
1600  patchDicts.setSize(nTotalPatches);
1601  for (label pI = nNonProcPatches; pI < nTotalPatches; ++pI)
1602  {
1603  patchDicts.set(pI, new dictionary());
1604  }
1605 
1606  label procAddI = 0;
1607 
1608  forAll(procUsed, pUI)
1609  {
1610  if (procUsed[pUI])
1611  {
1612  patchNames[nNonProcPatches + procAddI] =
1614 
1615  patchDicts[nNonProcPatches + procAddI].set
1616  (
1617  "type",
1618  processorPolyPatch::typeName
1619  );
1620 
1621  patchDicts[nNonProcPatches + procAddI].set
1622  (
1623  "myProcNo",
1625  );
1626 
1627  patchDicts[nNonProcPatches + procAddI].set("neighbProcNo", pUI);
1628 
1629  procAddI++;
1630  }
1631  }
1632  }
1633 
1634  return defaultPatchIndex;
1635 }
1636 
1637 
1638 Foam::vector Foam::conformalVoronoiMesh::calcSharedPatchNormal
1639 (
1640  Cell_handle c1,
1641  Cell_handle c2
1642 ) const
1643 {
1644  List<Foam::point> patchEdge(2, point::max);
1645 
1646  // Get shared Facet
1647  for (label cI = 0; cI < 4; ++cI)
1648  {
1649  if (c1->neighbor(cI) != c2 && !c1->vertex(cI)->constrained())
1650  {
1651  if (c1->vertex(cI)->internalBoundaryPoint())
1652  {
1653  patchEdge[0] = topoint(c1->vertex(cI)->point());
1654  }
1655  else
1656  {
1657  patchEdge[1] = topoint(c1->vertex(cI)->point());
1658  }
1659  }
1660  }
1661 
1662  Info<< " " << patchEdge << endl;
1663 
1664  return vector(patchEdge[1] - patchEdge[0]);
1665 }
1666 
1667 
1668 bool Foam::conformalVoronoiMesh::boundaryDualFace
1669 (
1670  Cell_handle c1,
1671  Cell_handle c2
1672 ) const
1673 {
1674  label nInternal = 0;
1675  label nExternal = 0;
1676 
1677  for (label cI = 0; cI < 4; ++cI)
1678  {
1679  if (c1->neighbor(cI) != c2 && !c1->vertex(cI)->constrained())
1680  {
1681  if (c1->vertex(cI)->internalBoundaryPoint())
1682  {
1683  nInternal++;
1684  }
1685  else if (c1->vertex(cI)->externalBoundaryPoint())
1686  {
1687  nExternal++;
1688  }
1689  }
1690  }
1691 
1692  Info<< "in = " << nInternal << " out = " << nExternal << endl;
1693 
1694  return (nInternal == 1 && nExternal == 1);
1695 }
1696 
1697 
1698 void Foam::conformalVoronoiMesh::createFacesOwnerNeighbourAndPatches
1699 (
1700  const pointField& pts,
1701  faceList& faces,
1702  labelList& owner,
1703  labelList& neighbour,
1705  PtrList<dictionary>& patchDicts,
1706  labelListList& patchPointPairSlaves,
1707  bitSet& boundaryFacesToRemove,
1708  bool includeEmptyPatches
1709 ) const
1710 {
1711  const label defaultPatchIndex = createPatchInfo(patchNames, patchDicts);
1712 
1713  const label nPatches = patchNames.size();
1714 
1715  labelList procNeighbours(nPatches);
1716  forAll(procNeighbours, patchi)
1717  {
1718  procNeighbours[patchi] =
1719  patchDicts[patchi].getOrDefault<label>("neighbProcNo", -1);
1720  }
1721 
1722  List<DynamicList<face>> patchFaces(nPatches, DynamicList<face>(0));
1723  List<DynamicList<label>> patchOwners(nPatches, DynamicList<label>(0));
1724  // Per patch face the index of the slave node of the point pair
1725  List<DynamicList<label>> patchPPSlaves(nPatches, DynamicList<label>(0));
1726 
1727  List<DynamicList<bool>> indirectPatchFace(nPatches, DynamicList<bool>(0));
1728 
1729 
1730  faces.setSize(number_of_finite_edges());
1731  owner.setSize(number_of_finite_edges());
1732  neighbour.setSize(number_of_finite_edges());
1733  boundaryFacesToRemove.setSize(number_of_finite_edges(), false);
1734 
1735  labelPairPairDynListList procPatchSortingIndex(nPatches);
1736 
1737  label dualFacei = 0;
1738 
1739  if (foamyHexMeshControls().guardFeaturePoints())
1740  {
1741  OBJstream startCellStr("startingCell.obj");
1742  OBJstream featurePointFacesStr("ftPtFaces.obj");
1743  OBJstream featurePointDualsStr("ftPtDuals.obj");
1744  OFstream cellStr("vertexCells.obj");
1745 
1746  label vcount = 1;
1747 
1748  for
1749  (
1750  Delaunay::Finite_vertices_iterator vit = finite_vertices_begin();
1751  vit != finite_vertices_end();
1752  ++vit
1753  )
1754  {
1755  if (vit->constrained())
1756  {
1757  // Find a starting cell
1758  std::list<Cell_handle> vertexCells;
1759  finite_incident_cells(vit, std::back_inserter(vertexCells));
1760 
1761  Cell_handle startCell;
1762 
1763  for
1764  (
1765  std::list<Cell_handle>::iterator vcit = vertexCells.begin();
1766  vcit != vertexCells.end();
1767  ++vcit
1768  )
1769  {
1770  if ((*vcit)->featurePointExternalCell())
1771  {
1772  startCell = *vcit;
1773  }
1774 
1775  if ((*vcit)->real())
1776  {
1777  featurePointDualsStr.write
1778  (
1779  linePointRef(topoint(vit->point()), (*vcit)->dual())
1780  );
1781  }
1782  }
1783 
1784  // Error if startCell is null
1785  if (startCell == nullptr)
1786  {
1787  Pout<< "Start cell is null!" << endl;
1788  }
1789 
1790  // Need to pick a direction to walk in
1791  Cell_handle vc1 = startCell;
1792  Cell_handle vc2;
1793 
1794  Info<< "c1 index = " << vc1->cellIndex() << " "
1795  << vc1->dual() << endl;
1796 
1797  for (label cI = 0; cI < 4; ++cI)
1798  {
1799  Info<< "c1 = " << cI << " "
1800  << vc1->neighbor(cI)->cellIndex() << " v = "
1801  << vc1->neighbor(cI)->dual() << endl;
1802 
1803  Info<< vc1->vertex(cI)->info();
1804  }
1805 
1806  Cell_handle nextCell;
1807 
1808  for (label cI = 0; cI < 4; ++cI)
1809  {
1810  if (vc1->vertex(cI)->externalBoundaryPoint())
1811  {
1812  vc2 = vc1->neighbor(cI);
1813 
1814  Info<< " c2 is neighbor "
1815  << vc2->cellIndex()
1816  << " of c1" << endl;
1817 
1818  for (label cI = 0; cI < 4; ++cI)
1819  {
1820  Info<< " c2 = " << cI << " "
1821  << vc2->neighbor(cI)->cellIndex() << " v = "
1822  << vc2->vertex(cI)->index() << endl;
1823  }
1824 
1825  face f(3);
1826  f[0] = vit->index();
1827  f[1] = vc1->cellIndex();
1828  f[2] = vc2->cellIndex();
1829 
1830  Info<< "f " << f << endl;
1831  forAll(f, pI)
1832  {
1833  Info<< " " << pts[f[pI]] << endl;
1834  }
1835 
1836  vector correctNormal = calcSharedPatchNormal(vc1, vc2);
1837  correctNormal.normalise();
1838 
1839  Info<< " cN " << correctNormal << endl;
1840 
1841  vector fN = f.areaNormal(pts);
1842 
1843  if (mag(fN) < SMALL)
1844  {
1845  nextCell = vc2;
1846  continue;
1847  }
1848 
1849  fN.normalise();
1850  Info<< " fN " << fN << endl;
1851 
1852  if ((fN & correctNormal) > 0)
1853  {
1854  nextCell = vc2;
1855  break;
1856  }
1857  }
1858  }
1859 
1860  vc2 = nextCell;
1861 
1862  label own = vit->index();
1863  face f(3);
1864  f[0] = own;
1865 
1866  Info<< "Start walk from " << vc1->cellIndex()
1867  << " to " << vc2->cellIndex() << endl;
1868 
1869  // Walk while not at start cell
1870 
1871  label iter = 0;
1872  do
1873  {
1874  Info<< " Walk from " << vc1->cellIndex()
1875  << " " << vc1->dual()
1876  << " to " << vc2->cellIndex()
1877  << " " << vc2->dual()
1878  << endl;
1879 
1880  startCellStr.write(linePointRef(vc1->dual(), vc2->dual()));
1881 
1882  // Get patch by getting face between cells and the two
1883  // points on the face that are not the feature vertex
1884  label patchIndex =
1885  geometryToConformTo_.findPatch
1886  (
1887  topoint(vit->point())
1888  );
1889 
1890  f[1] = vc1->cellIndex();
1891  f[2] = vc2->cellIndex();
1892 
1893  patchFaces[patchIndex].append(f);
1894  patchOwners[patchIndex].append(own);
1895  patchPPSlaves[patchIndex].append(own);
1896 
1897  // Find next cell
1898  Cell_handle nextCell;
1899 
1900  Info<< " c1 vertices " << vc2->dual() << endl;
1901  for (label cI = 0; cI < 4; ++cI)
1902  {
1903  Info<< " " << vc2->vertex(cI)->info();
1904  }
1905  Info<< " c1 neighbour vertices " << endl;
1906  for (label cI = 0; cI < 4; ++cI)
1907  {
1908  if
1909  (
1910  !vc2->vertex(cI)->constrained()
1911  && vc2->neighbor(cI) != vc1
1912  && !is_infinite(vc2->neighbor(cI))
1913  &&
1914  (
1915  vc2->neighbor(cI)->featurePointExternalCell()
1916  || vc2->neighbor(cI)->featurePointInternalCell()
1917  )
1918  && vc2->neighbor(cI)->hasConstrainedPoint()
1919  )
1920  {
1922  (
1923  cellStr,
1924  vc2->neighbor(cI),
1925  vcount++
1926  );
1927 
1928  Info<< " neighbour " << cI << " "
1929  << vc2->neighbor(cI)->dual() << endl;
1930  for (label I = 0; I < 4; ++I)
1931  {
1932  Info<< " "
1933  << vc2->neighbor(cI)->vertex(I)->info();
1934  }
1935  }
1936  }
1937 
1938  for (label cI = 0; cI < 4; ++cI)
1939  {
1940  if
1941  (
1942  !vc2->vertex(cI)->constrained()
1943  && vc2->neighbor(cI) != vc1
1944  && !is_infinite(vc2->neighbor(cI))
1945  &&
1946  (
1947  vc2->neighbor(cI)->featurePointExternalCell()
1948  || vc2->neighbor(cI)->featurePointInternalCell()
1949  )
1950  && vc2->neighbor(cI)->hasConstrainedPoint()
1951  )
1952  {
1953  // check if shared edge is internal/internal
1954  if (boundaryDualFace(vc2, vc2->neighbor(cI)))
1955  {
1956  nextCell = vc2->neighbor(cI);
1957  break;
1958  }
1959  }
1960  }
1961 
1962  vc1 = vc2;
1963  vc2 = nextCell;
1964 
1965  iter++;
1966  } while (vc1 != startCell && iter < 100);
1967  }
1968  }
1969  }
1970 
1971  for
1972  (
1973  Delaunay::Finite_edges_iterator eit = finite_edges_begin();
1974  eit != finite_edges_end();
1975  ++eit
1976  )
1977  {
1978  Cell_handle c = eit->first;
1979  Vertex_handle vA = c->vertex(eit->second);
1980  Vertex_handle vB = c->vertex(eit->third);
1981 
1982  if (vA->constrained() && vB->constrained())
1983  {
1984  continue;
1985  }
1986 
1987  if
1988  (
1989  (vA->constrained() && vB->internalOrBoundaryPoint())
1990  || (vB->constrained() && vA->internalOrBoundaryPoint())
1991  )
1992  {
1993  face newDualFace = buildDualFace(eit);
1994 
1995  label own = -1;
1996  label nei = -1;
1997 
1998  if (ownerAndNeighbour(vA, vB, own, nei))
1999  {
2000  reverse(newDualFace);
2001  }
2002 
2003  // internal face
2004  faces[dualFacei] = newDualFace;
2005  owner[dualFacei] = own;
2006  neighbour[dualFacei] = nei;
2007 
2008  dualFacei++;
2009  }
2010  else if
2011  (
2012  (vA->internalOrBoundaryPoint() && !vA->referred())
2013  || (vB->internalOrBoundaryPoint() && !vB->referred())
2014  )
2015  {
2016  if
2017  (
2018  (vA->internalPoint() && vB->externalBoundaryPoint())
2019  || (vB->internalPoint() && vA->externalBoundaryPoint())
2020  )
2021  {
2022  Cell_circulator ccStart = incident_cells(*eit);
2023  Cell_circulator cc1 = ccStart;
2024  Cell_circulator cc2 = cc1;
2025 
2026  cc2++;
2027 
2028  bool skipEdge = false;
2029 
2030  do
2031  {
2032  if
2033  (
2034  cc1->hasFarPoint() || cc2->hasFarPoint()
2035  || is_infinite(cc1) || is_infinite(cc2)
2036  )
2037  {
2038  Pout<< "Ignoring edge between internal and external: "
2039  << vA->info()
2040  << vB->info();
2041 
2042  skipEdge = true;
2043  break;
2044  }
2045 
2046  cc1++;
2047  cc2++;
2048 
2049  } while (cc1 != ccStart);
2050 
2051 
2052  // Do not create faces if the internal point is outside!
2053  // This occurs because the internal point is not determined to
2054  // be outside in the inside/outside test. This is most likely
2055  // due to the triangle.nearestPointClassify test not returning
2056  // edge/point as the nearest type.
2057 
2058  if (skipEdge)
2059  {
2060  continue;
2061  }
2062  }
2063 
2064  face newDualFace = buildDualFace(eit);
2065 
2066  if (newDualFace.size() >= 3)
2067  {
2068  label own = -1;
2069  label nei = -1;
2070 
2071  if (ownerAndNeighbour(vA, vB, own, nei))
2072  {
2073  reverse(newDualFace);
2074  }
2075 
2076  label patchIndex = -1;
2077 
2078  pointFromPoint ptA = topoint(vA->point());
2079  pointFromPoint ptB = topoint(vB->point());
2080 
2081  if (nei == -1)
2082  {
2083  // boundary face
2084 
2085  if (isProcBoundaryEdge(eit))
2086  {
2087  // One (and only one) of the points is an internal
2088  // point from another processor
2089 
2090  label procIndex = max(vA->procIndex(), vB->procIndex());
2091 
2092  patchIndex = max
2093  (
2094  procNeighbours.find(vA->procIndex()),
2095  procNeighbours.find(vB->procIndex())
2096  );
2097 
2098  // The lower processor index is the owner of the
2099  // two for the purpose of sorting the patch faces.
2100 
2101  if (Pstream::myProcNo() < procIndex)
2102  {
2103  // Use this processor's vertex index as the master
2104  // for sorting
2105 
2106  DynamicList<labelPairPair>& sortingIndex =
2107  procPatchSortingIndex[patchIndex];
2108 
2109  if (vB->internalOrBoundaryPoint() && vB->referred())
2110  {
2111  sortingIndex.append
2112  (
2114  (
2115  labelPair(vA->index(), vA->procIndex()),
2116  labelPair(vB->index(), vB->procIndex())
2117  )
2118  );
2119  }
2120  else
2121  {
2122  sortingIndex.append
2123  (
2125  (
2126  labelPair(vB->index(), vB->procIndex()),
2127  labelPair(vA->index(), vA->procIndex())
2128  )
2129  );
2130  }
2131  }
2132  else
2133  {
2134  // Use the other processor's vertex index as the
2135  // master for sorting
2136 
2137  DynamicList<labelPairPair>& sortingIndex =
2138  procPatchSortingIndex[patchIndex];
2139 
2140  if (vA->internalOrBoundaryPoint() && vA->referred())
2141  {
2142  sortingIndex.append
2143  (
2145  (
2146  labelPair(vA->index(), vA->procIndex()),
2147  labelPair(vB->index(), vB->procIndex())
2148  )
2149  );
2150  }
2151  else
2152  {
2153  sortingIndex.append
2154  (
2156  (
2157  labelPair(vB->index(), vB->procIndex()),
2158  labelPair(vA->index(), vA->procIndex())
2159  )
2160  );
2161  }
2162  }
2163 
2164 // Pout<< ptA << " " << ptB
2165 // << " proc indices "
2166 // << vA->procIndex() << " " << vB->procIndex()
2167 // << " indices " << vA->index()
2168 // << " " << vB->index()
2169 // << " my proc " << Pstream::myProcNo()
2170 // << " addedIndex "
2171 // << procPatchSortingIndex[patchIndex].last()
2172 // << endl;
2173  }
2174  else
2175  {
2176  patchIndex = geometryToConformTo_.findPatch(ptA, ptB);
2177  }
2178 
2179  if (patchIndex == -1)
2180  {
2181  // Did not find a surface patch between
2182  // between Dv pair, finding nearest patch
2183 
2184 // Pout<< "Did not find a surface patch between "
2185 // << "for face, finding nearest patch to"
2186 // << 0.5*(ptA + ptB) << endl;
2187 
2188  patchIndex = geometryToConformTo_.findPatch
2189  (
2190  0.5*(ptA + ptB)
2191  );
2192  }
2193 
2194  patchFaces[patchIndex].append(newDualFace);
2195  patchOwners[patchIndex].append(own);
2196 
2197  // If the two vertices are a pair, then the patch face is
2198  // a desired one.
2199  if
2200  (
2201  vA->boundaryPoint() && vB->boundaryPoint()
2202  && !ptPairs_.isPointPair(vA, vB)
2203  && !ftPtConformer_.featurePointPairs().isPointPair(vA, vB)
2204  )
2205  {
2206  indirectPatchFace[patchIndex].append(true);
2207  }
2208  else
2209  {
2210  indirectPatchFace[patchIndex].append(false);
2211  }
2212 
2213  // Store the non-internal or boundary point
2214  if (vA->internalOrBoundaryPoint())
2215  {
2216  patchPPSlaves[patchIndex].append(vB->index());
2217  }
2218  else
2219  {
2220  patchPPSlaves[patchIndex].append(vA->index());
2221  }
2222  }
2223  else
2224  {
2225  if
2226  (
2227  !vA->boundaryPoint()
2228  || !vB->boundaryPoint()
2229  || ptPairs_.isPointPair(vA, vB)
2230  || ftPtConformer_.featurePointPairs().isPointPair(vA, vB)
2231  )
2232  {
2233  patchIndex = geometryToConformTo_.findPatch(ptA, ptB);
2234  }
2235 
2236  if
2237  (
2238  patchIndex != -1
2239  && geometryToConformTo_.patchInfo().set(patchIndex)
2240  )
2241  {
2242  // baffle faces
2243 
2244  patchFaces[patchIndex].append(newDualFace);
2245  patchOwners[patchIndex].append(own);
2246  indirectPatchFace[patchIndex].append(false);
2247 
2248  reverse(newDualFace);
2249 
2250  patchFaces[patchIndex].append(newDualFace);
2251  patchOwners[patchIndex].append(nei);
2252  indirectPatchFace[patchIndex].append(false);
2253 
2254  if
2255  (
2256  labelPair(vB->index(), vB->procIndex())
2257  < labelPair(vA->index(), vA->procIndex())
2258  )
2259  {
2260  patchPPSlaves[patchIndex].append(vB->index());
2261  patchPPSlaves[patchIndex].append(vB->index());
2262  }
2263  else
2264  {
2265  patchPPSlaves[patchIndex].append(vA->index());
2266  patchPPSlaves[patchIndex].append(vA->index());
2267  }
2268 
2269  }
2270  else
2271  {
2272  // internal face
2273  faces[dualFacei] = newDualFace;
2274  owner[dualFacei] = own;
2275  neighbour[dualFacei] = nei;
2276 
2277  dualFacei++;
2278  }
2279  }
2280  }
2281  }
2282  }
2283 
2284  if (!patchFaces[defaultPatchIndex].empty())
2285  {
2286  Pout<< nl << patchFaces[defaultPatchIndex].size()
2287  << " faces were not able to have their patch determined from "
2288  << "the surface. "
2289  << nl << "Adding to patch " << patchNames[defaultPatchIndex]
2290  << endl;
2291  }
2292 
2293  label nInternalFaces = dualFacei;
2294 
2295  faces.setSize(nInternalFaces);
2296  owner.setSize(nInternalFaces);
2297  neighbour.setSize(nInternalFaces);
2298 
2299  timeCheck("polyMesh quality checked");
2300 
2301  sortFaces(faces, owner, neighbour);
2302 
2303  sortProcPatches
2304  (
2305  patchFaces,
2306  patchOwners,
2307  patchPPSlaves,
2308  procPatchSortingIndex
2309  );
2310 
2311  timeCheck("faces, owner, neighbour sorted");
2312 
2313  addPatches
2314  (
2315  nInternalFaces,
2316  faces,
2317  owner,
2318  patchDicts,
2319  boundaryFacesToRemove,
2320  patchFaces,
2321  patchOwners,
2322  indirectPatchFace
2323  );
2324 
2325  // Return patchPointPairSlaves.setSize(nPatches);
2326  patchPointPairSlaves.setSize(nPatches);
2327  forAll(patchPPSlaves, patchi)
2328  {
2329  patchPointPairSlaves[patchi].transfer(patchPPSlaves[patchi]);
2330  }
2331 
2332  if (foamyHexMeshControls().objOutput())
2333  {
2334  Info<< "Writing processor interfaces" << endl;
2335 
2336  forAll(patchDicts, nbI)
2337  {
2338  if (patchFaces[nbI].size() > 0)
2339  {
2340  const label neighbour =
2341  patchDicts[nbI].getOrDefault<label>("neighbProcNo", -1);
2342 
2343  faceList procPatchFaces = patchFaces[nbI];
2344 
2345  // Reverse faces as it makes it easier to analyse the output
2346  // using a diff
2347  if (neighbour < Pstream::myProcNo())
2348  {
2349  forAll(procPatchFaces, fI)
2350  {
2351  procPatchFaces[fI] = procPatchFaces[fI].reverseFace();
2352  }
2353  }
2354 
2355  if (neighbour != -1)
2356  {
2357  word fName =
2358  "processor_"
2359  + name(Pstream::myProcNo())
2360  + "_to_"
2361  + name(neighbour)
2362  + "_interface.obj";
2363 
2365  (
2366  time().path()/fName,
2367  *this,
2368  procPatchFaces
2369  );
2370  }
2371  }
2372  }
2373  }
2374 }
2375 
2376 
2377 void Foam::conformalVoronoiMesh::sortFaces
2378 (
2379  faceList& faces,
2380  labelList& owner,
2381  labelList& neighbour
2382 ) const
2383 {
2384  // Upper triangular order:
2385  // + owner is sorted in ascending cell order
2386  // + within each block of equal value for owner, neighbour is sorted in
2387  // ascending cell order.
2388  // + faces sorted to correspond
2389  // e.g.
2390  // owner | neighbour
2391  // 0 | 2
2392  // 0 | 23
2393  // 0 | 71
2394  // 1 | 23
2395  // 1 | 24
2396  // 1 | 91
2397 
2398  List<labelPair> ownerNeighbourPair(owner.size());
2399 
2400  forAll(ownerNeighbourPair, oNI)
2401  {
2402  ownerNeighbourPair[oNI] = labelPair(owner[oNI], neighbour[oNI]);
2403  }
2404 
2405  Info<< nl
2406  << "Sorting faces, owner and neighbour into upper triangular order"
2407  << endl;
2408 
2409  labelList oldToNew(sortedOrder(ownerNeighbourPair));
2410  oldToNew = invert(oldToNew.size(), oldToNew);
2411 
2412  inplaceReorder(oldToNew, faces);
2413  inplaceReorder(oldToNew, owner);
2414  inplaceReorder(oldToNew, neighbour);
2415 }
2416 
2417 
2418 void Foam::conformalVoronoiMesh::sortProcPatches
2419 (
2420  List<DynamicList<face>>& patchFaces,
2421  List<DynamicList<label>>& patchOwners,
2422  List<DynamicList<label>>& patchPointPairSlaves,
2423  labelPairPairDynListList& patchSortingIndices
2424 ) const
2425 {
2426  if (!Pstream::parRun())
2427  {
2428  return;
2429  }
2430 
2431  forAll(patchSortingIndices, patchi)
2432  {
2433  faceList& faces = patchFaces[patchi];
2434  labelList& owner = patchOwners[patchi];
2435  DynamicList<label>& slaves = patchPointPairSlaves[patchi];
2436  DynamicList<labelPairPair>& sortingIndices
2437  = patchSortingIndices[patchi];
2438 
2439  if (!sortingIndices.empty())
2440  {
2441  if
2442  (
2443  faces.size() != sortingIndices.size()
2444  || owner.size() != sortingIndices.size()
2445  || slaves.size() != sortingIndices.size()
2446  )
2447  {
2449  << "patch size and size of sorting indices is inconsistent "
2450  << " for patch " << patchi << nl
2451  << " faces.size() " << faces.size() << nl
2452  << " owner.size() " << owner.size() << nl
2453  << " slaves.size() " << slaves.size() << nl
2454  << " sortingIndices.size() "
2455  << sortingIndices.size()
2456  << exit(FatalError) << endl;
2457  }
2458 
2459  labelList oldToNew(sortedOrder(sortingIndices));
2460  oldToNew = invert(oldToNew.size(), oldToNew);
2461 
2462  inplaceReorder(oldToNew, sortingIndices);
2463  inplaceReorder(oldToNew, faces);
2464  inplaceReorder(oldToNew, owner);
2465  inplaceReorder(oldToNew, slaves);
2466  }
2467  }
2468 }
2469 
2470 
2471 void Foam::conformalVoronoiMesh::addPatches
2472 (
2473  const label nInternalFaces,
2474  faceList& faces,
2475  labelList& owner,
2476  PtrList<dictionary>& patchDicts,
2477  bitSet& boundaryFacesToRemove,
2478  const List<DynamicList<face>>& patchFaces,
2479  const List<DynamicList<label>>& patchOwners,
2480  const List<DynamicList<bool>>& indirectPatchFace
2481 ) const
2482 {
2483  label nBoundaryFaces = 0;
2484 
2485  forAll(patchFaces, p)
2486  {
2487  patchDicts[p].set("nFaces", patchFaces[p].size());
2488  patchDicts[p].set("startFace", nInternalFaces + nBoundaryFaces);
2489 
2490  nBoundaryFaces += patchFaces[p].size();
2491  }
2492 
2493  faces.setSize(nInternalFaces + nBoundaryFaces);
2494  owner.setSize(nInternalFaces + nBoundaryFaces);
2495  boundaryFacesToRemove.setSize(nInternalFaces + nBoundaryFaces);
2496 
2497  label facei = nInternalFaces;
2498 
2499  forAll(patchFaces, p)
2500  {
2501  forAll(patchFaces[p], f)
2502  {
2503  faces[facei] = patchFaces[p][f];
2504  owner[facei] = patchOwners[p][f];
2505  boundaryFacesToRemove[facei] = indirectPatchFace[p][f];
2506 
2507  facei++;
2508  }
2509  }
2510 }
2511 
2512 
2513 void Foam::conformalVoronoiMesh::removeUnusedPoints
2514 (
2515  faceList& faces,
2516  pointField& pts,
2517  labelList& boundaryPts
2518 ) const
2519 {
2520  Info<< nl << "Removing unused points" << endl;
2521 
2522  bitSet ptUsed(pts.size(), false);
2523 
2524  // Scan all faces to find all of the points that are used
2525 
2526  forAll(faces, fI)
2527  {
2528  const face& f = faces[fI];
2529 
2530  ptUsed.set(f);
2531  }
2532 
2533  label pointi = 0;
2534 
2535  labelList oldToNew(pts.size(), label(-1));
2536 
2537  // Move all of the used points to the start of the pointField and
2538  // truncate it
2539 
2540  forAll(ptUsed, ptUI)
2541  {
2542  if (ptUsed.test(ptUI))
2543  {
2544  oldToNew[ptUI] = pointi++;
2545  }
2546  }
2547 
2548  inplaceReorder(oldToNew, pts);
2549  inplaceReorder(oldToNew, boundaryPts);
2550 
2551  Info<< " Removing "
2552  << returnReduce(pts.size() - pointi, sumOp<label>())
2553  << " unused points"
2554  << endl;
2555 
2556  pts.setSize(pointi);
2557  boundaryPts.setSize(pointi);
2558 
2559  // Renumber the faces to use the new point numbers
2560 
2561  forAll(faces, fI)
2562  {
2563  inplaceRenumber(oldToNew, faces[fI]);
2564  }
2565 }
2566 
2567 
2568 Foam::labelList Foam::conformalVoronoiMesh::removeUnusedCells
2569 (
2570  labelList& owner,
2571  labelList& neighbour
2572 ) const
2573 {
2574  Info<< nl << "Removing unused cells" << endl;
2575 
2576  bitSet cellUsed(vertexCount(), false);
2577 
2578  // Scan all faces to find all of the cells that are used
2579 
2580  cellUsed.set(owner);
2581  cellUsed.set(neighbour);
2582 
2583  label celli = 0;
2584 
2585  labelList oldToNew(cellUsed.size(), label(-1));
2586 
2587  // Move all of the used cellCentres to the start of the pointField and
2588  // truncate it
2589 
2590  forAll(cellUsed, cellUI)
2591  {
2592  if (cellUsed.test(cellUI))
2593  {
2594  oldToNew[cellUI] = celli++;
2595  }
2596  }
2597 
2598  labelList newToOld(invert(celli, oldToNew));
2599 
2600  // Find all of the unused cells, create a list of them, then
2601  // subtract one from each owner and neighbour entry for each of
2602  // the unused cell indices that it is above.
2603 
2604  DynamicList<label> unusedCells;
2605 
2606  forAll(cellUsed, cUI)
2607  {
2608  if (!cellUsed.test(cUI))
2609  {
2610  unusedCells.append(cUI);
2611  }
2612  }
2613 
2614  if (unusedCells.size() > 0)
2615  {
2616  Info<< " Removing "
2617  << returnReduce(unusedCells.size(), sumOp<label>())
2618  << " unused cell labels" << endl;
2619 
2620  forAll(owner, oI)
2621  {
2622  label& o = owner[oI];
2623 
2624  o -= findLower(unusedCells, o) + 1;
2625  }
2626 
2627  forAll(neighbour, nI)
2628  {
2629  label& n = neighbour[nI];
2630 
2631  n -= findLower(unusedCells, n) + 1;
2632  }
2633  }
2634 
2635  return newToOld;
2636 }
2637 
2638 
2639 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::IOobject::NO_WRITE
Definition: IOobject.H:130
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:71
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:396
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
nPatches
label nPatches
Definition: readKivaGrid.H:396
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::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:427
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::UPstream::parRun
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:415
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:69
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:435
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:350
Foam::dictionary::get
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:81
Foam::labelPairPair
Pair< labelPair > labelPairPair
A pair of labelPairs.
Definition: labelPair.H:63
Foam::Pout
prefixOSstream Pout
An Ostream wrapper for parallel output to std::cout.
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:59
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
backgroundMeshDecomposition.H
Foam::primitiveMesh::nCells
label nCells() const
Number of mesh cells.
Definition: primitiveMeshI.H:96
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 (uses stdout - output is on the master only)
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
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:528
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: PtrListI.H:108
Foam::IOstream::info
InfoProxy< IOstream > info() const
Return info proxy.
Definition: IOstream.H:404
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 a pointer to a new patch created on freestore from.
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::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:445
Foam::autoPtr< Foam::polyMesh >
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::linePointRef
line< point, const point & > linePointRef
Line using referred points.
Definition: linePointRef.H:47
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:372
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
Definition: pointIndexHit.H:45
Foam::nl
constexpr char nl
Definition: Ostream.H:385
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:74
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::labelPairHashSet
HashSet< labelPair, labelPair::Hash<> > labelPairHashSet
A HashSet for a labelPair. The hashing is based on labelPair (FixedList) and is thus non-commutative.
Definition: labelPairHashes.H:65
Foam::List< label >
Foam::processorPolyPatch::newName
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
Definition: processorPolyPatch.C:186
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:181
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:325
Foam::constant::universal::c
const dimensionedScalar c
Speed of light in a vacuum.
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.
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::labelUList
UList< label > labelUList
A UList of labels.
Definition: UList.H:80
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys and label hasher.
Definition: HashSet.H:410
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
indexedCellOps.H
Foam::IOobject::NO_READ
Definition: IOobject.H:123
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:298
OBJstream.H
Foam::I
static const Identity< scalar > I
Definition: Identity.H:95
conformalVoronoiMesh.H
indexedCellChecks.H
Foam::keyType::REGEX_RECURSIVE
Definition: keyType.H:79