edgeCollapser.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2019-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 "edgeCollapser.H"
30 #include "polyMesh.H"
31 #include "polyTopoChange.H"
32 #include "globalMeshData.H"
33 #include "syncTools.H"
34 #include "PointEdgeWave.H"
35 #include "globalIndex.H"
36 #include "removePoints.H"
37 #include "motionSmoother.H"
38 #include "OFstream.H"
39 
40 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44 defineTypeNameAndDebug(edgeCollapser, 0);
45 }
46 
47 
49 (
50  const polyMesh& mesh,
51  const dictionary& meshQualityDict
52 )
53 {
54  labelHashSet badFaces(mesh.nFaces()/100);
55  DynamicList<label> checkFaces(mesh.nFaces());
56 
57  const vectorField& fAreas = mesh.faceAreas();
58 
59  scalar faceAreaLimit = SMALL;
60 
61  forAll(fAreas, facei)
62  {
63  if (mag(fAreas[facei]) > faceAreaLimit)
64  {
65  checkFaces.append(facei);
66  }
67  }
68 
69  Info<< endl;
70 
71  motionSmoother::checkMesh
72  (
73  false,
74  mesh,
75  meshQualityDict,
76  checkFaces,
77  badFaces
78  );
79 
80  return badFaces;
81 }
82 
83 
85 (
86  const polyMesh& mesh,
87  const dictionary& meshQualityDict,
88  bitSet& isErrorPoint
89 )
90 {
91  labelHashSet badFaces = edgeCollapser::checkBadFaces
92  (
93  mesh,
94  meshQualityDict
95  );
96 
97  label nBadFaces = returnReduce(badFaces.size(), sumOp<label>());
98 
99  for (const label facei : badFaces)
100  {
101  const face& f = mesh.faces()[facei];
102 
103  isErrorPoint.set(f);
104  }
105 
106  syncTools::syncPointList
107  (
108  mesh,
109  isErrorPoint,
111  0
112  );
113 
114  return nBadFaces;
115 }
116 
117 
118 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
119 
120 Foam::labelList Foam::edgeCollapser::edgesFromPoints
121 (
122  const label& facei,
123  const labelList& pointLabels
124 ) const
125 {
126  labelList edgeLabels(pointLabels.size() - 1, -1);
127 
128  const labelList& faceEdges = mesh_.faceEdges()[facei];
129  const edgeList& edges = mesh_.edges();
130 
131  label count = 0;
132 
133  forAll(faceEdges, eI)
134  {
135  const label edgeI = faceEdges[eI];
136  const edge& e = edges[edgeI];
137 
138  label match = 0;
139 
140  forAll(pointLabels, pI)
141  {
142  if (e[0] == pointLabels[pI])
143  {
144  match++;
145  }
146 
147  if (e[1] == pointLabels[pI])
148  {
149  match++;
150  }
151  }
152 
153  if (match == 2)
154  {
155  // Edge found
156  edgeLabels[count++] = edgeI;
157  }
158  }
159 
160  if (count != edgeLabels.size())
161  {
162  edgeLabels.setSize(count);
163  }
164 
165  return edgeLabels;
166 }
167 
168 
169 void Foam::edgeCollapser::collapseToEdge
170 (
171  const label facei,
172  const pointField& pts,
173  const labelList& pointPriority,
174  const vector& collapseAxis,
175  const point& fC,
176  const labelList& facePtsNeg,
177  const labelList& facePtsPos,
178  const scalarList& dNeg,
179  const scalarList& dPos,
180  const scalar dShift,
181  bitSet& collapseEdge,
182  Map<point>& collapsePointToLocation
183 ) const
184 {
185  // Negative half
186 
187  Foam::point collapseToPtA(GREAT, GREAT, GREAT);
188  //collapseAxis*(sum(dNeg)/dNeg.size() - dShift) + fC;
189 
190  label maxPriority = labelMin;
191  DynamicList<label> maxPriorityPts(max(dNeg.size(), dPos.size()));
192 
193  forAll(facePtsNeg, fPtI)
194  {
195  const label facePointi = facePtsNeg[fPtI];
196  const label facePtPriority = pointPriority[facePointi];
197 
198  if (facePtPriority > maxPriority)
199  {
200  maxPriority = facePtPriority;
201  maxPriorityPts.clear();
202  maxPriorityPts.append(facePointi);
203  }
204  else if (facePtPriority == maxPriority)
205  {
206  maxPriorityPts.append(facePointi);
207  }
208  }
209 
210  if (!maxPriorityPts.empty())
211  {
212  Foam::point averagePt(Zero);
213 
214  forAll(maxPriorityPts, ptI)
215  {
216  averagePt += pts[maxPriorityPts[ptI]];
217  }
218 
219  collapseToPtA = averagePt/maxPriorityPts.size();
220 // collapseToPtA = pts[maxPriorityPts.first()];
221  }
222 
223  maxPriority = labelMin;
224  maxPriorityPts.clear();
225 
226  labelList faceEdgesNeg = edgesFromPoints(facei, facePtsNeg);
227 
228  collapseEdge.set(faceEdgesNeg);
229 
230  forAll(facePtsNeg, pI)
231  {
232  collapsePointToLocation.set(facePtsNeg[pI], collapseToPtA);
233  }
234 
235 
236  // Positive half
237  Foam::point collapseToPtB(GREAT, GREAT, GREAT);
238 // = collapseAxis*(sum(dPos)/dPos.size() - dShift) + fC;
239 
240  forAll(facePtsPos, fPtI)
241  {
242  const label facePointi = facePtsPos[fPtI];
243  const label facePtPriority = pointPriority[facePointi];
244 
245  if (facePtPriority > maxPriority)
246  {
247  maxPriority = facePtPriority;
248  maxPriorityPts.clear();
249  maxPriorityPts.append(facePointi);
250  }
251  else if (facePtPriority == maxPriority)
252  {
253  maxPriorityPts.append(facePointi);
254  }
255  }
256 
257  if (!maxPriorityPts.empty())
258  {
259  Foam::point averagePt(Zero);
260 
261  forAll(maxPriorityPts, ptI)
262  {
263  averagePt += pts[maxPriorityPts[ptI]];
264  }
265 
266  collapseToPtB = averagePt/maxPriorityPts.size();
267 // collapseToPtB = pts[maxPriorityPts.first()];
268  }
269 
270  labelList faceEdgesPos = edgesFromPoints(facei, facePtsPos);
271 
272  collapseEdge.set(faceEdgesPos);
273 
274  forAll(facePtsPos, pI)
275  {
276  collapsePointToLocation.set(facePtsPos[pI], collapseToPtB);
277  }
278 }
279 
280 
281 void Foam::edgeCollapser::collapseToPoint
282 (
283  const label& facei,
284  const pointField& pts,
285  const labelList& pointPriority,
286  const point& fC,
287  const labelList& facePts,
288  bitSet& collapseEdge,
289  Map<point>& collapsePointToLocation
290 ) const
291 {
292  const face& f = mesh_.faces()[facei];
293 
294  Foam::point collapseToPt = fC;
295 
296  label maxPriority = labelMin;
297  DynamicList<label> maxPriorityPts(f.size());
298 
299  forAll(facePts, fPtI)
300  {
301  const label facePointi = facePts[fPtI];
302  const label facePtPriority = pointPriority[facePointi];
303 
304  if (facePtPriority > maxPriority)
305  {
306  maxPriority = facePtPriority;
307  maxPriorityPts.clear();
308  maxPriorityPts.append(facePointi);
309  }
310  else if (facePtPriority == maxPriority)
311  {
312  maxPriorityPts.append(facePointi);
313  }
314  }
315 
316  if (!maxPriorityPts.empty())
317  {
318  Foam::point averagePt(Zero);
319 
320  forAll(maxPriorityPts, ptI)
321  {
322  averagePt += pts[maxPriorityPts[ptI]];
323  }
324 
325  collapseToPt = averagePt/maxPriorityPts.size();
326 
327 // collapseToPt = pts[maxPriorityPts.first()];
328  }
329 
330 // DynamicList<label> faceBoundaryPts(f.size());
331 // DynamicList<label> faceFeaturePts(f.size());
332 //
333 // forAll(facePts, fPtI)
334 // {
335 // if (pointPriority[facePts[fPtI]] == 1)
336 // {
337 // faceFeaturePts.append(facePts[fPtI]);
338 // }
339 // else if (pointPriority[facePts[fPtI]] == 0)
340 // {
341 // faceBoundaryPts.append(facePts[fPtI]);
342 // }
343 // }
344 //
345 // if (!faceBoundaryPts.empty() || !faceFeaturePts.empty())
346 // {
347 // if (!faceFeaturePts.empty())
348 // {
349 // collapseToPt = pts[faceFeaturePts.first()];
350 // }
351 // else if (faceBoundaryPts.size() == 2)
352 // {
353 // collapseToPt =
354 // 0.5
355 // *(
356 // pts[faceBoundaryPts[0]]
357 // + pts[faceBoundaryPts[1]]
358 // );
359 // }
360 // else if (faceBoundaryPts.size() <= f.size())
361 // {
362 // face bFace(faceBoundaryPts);
363 //
364 // collapseToPt = bFace.centre(pts);
365 // }
366 // }
367 
368  const labelList& faceEdges = mesh_.faceEdges()[facei];
369 
370  collapseEdge.set(faceEdges);
371 
372  forAll(f, pI)
373  {
374  collapsePointToLocation.set(f[pI], collapseToPt);
375  }
376 }
377 
378 
379 void Foam::edgeCollapser::faceCollapseAxisAndAspectRatio
380 (
381  const face& f,
382  const point& fC,
383  vector& collapseAxis,
384  scalar& aspectRatio
385 ) const
386 {
387  const pointField& pts = mesh_.points();
388 
389  symmTensor J(symm(f.inertia(pts, fC)));
390 
391  // Find the dominant collapse direction by finding the eigenvector
392  // that corresponds to the normal direction, discarding it. The
393  // eigenvector corresponding to the smaller of the two remaining
394  // eigenvalues is the dominant axis in a high aspect ratio face.
395 
396  scalar magJ = mag(J);
397 
398  scalar detJ = SMALL;
399 
400  if (magJ > VSMALL)
401  {
402  // Normalise inertia tensor to remove problems with small values
403 
404  J /= mag(J);
405  // J /= cmptMax(J);
406  // J /= max(eigenValues(J).x(), SMALL);
407 
408  // Calculating determinant, including stabilisation for zero or
409  // small negative values
410 
411  detJ = max(det(J), SMALL);
412  }
413 
414  if (detJ < 1e-5)
415  {
416  // It is possible that all the points of a face are the same
417 
418  collapseAxis = f.edges()[f.longestEdge(pts)].unitVec(pts);
419 
420  // Empirical correlation for high aspect ratio faces
421 
422  aspectRatio = Foam::sqrt(0.35/detJ);
423  }
424  else
425  {
426  vector eVals(eigenValues(J));
427 
428  if (mag(eVals.y() - eVals.x()) < 100*SMALL)
429  {
430  // First two eigenvalues are the same: i.e. a square face
431 
432  // Cannot necessarily determine linearly independent
433  // eigenvectors, or any at all, use longest edge direction.
434 
435  collapseAxis = f.edges()[f.longestEdge(pts)].unitVec(pts);
436 
437  aspectRatio = 1.0;
438  }
439  else
440  {
441  // The maximum eigenvalue (z()) must be the direction of the
442  // normal, as it has the greatest value. The minimum eigenvalue
443  // is the dominant collapse axis for high aspect ratio faces.
444 
445  collapseAxis = eigenVectors(J, eVals).x();
446 
447  // The inertia calculation describes the mass distribution as a
448  // function of distance squared to the axis, so the square root of
449  // the ratio of face-plane moments gives a good indication of the
450  // aspect ratio.
451 
452  aspectRatio = Foam::sqrt(eVals.y()/max(eVals.x(), SMALL));
453  }
454  }
455 }
456 
457 
458 Foam::scalarField Foam::edgeCollapser::calcTargetFaceSizes() const
459 {
460  scalarField targetFaceSizes(mesh_.nFaces(), -1);
461 
462  const scalarField& V = mesh_.cellVolumes();
463  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
464 
465  const labelList& cellOwner = mesh_.faceOwner();
466  const labelList& cellNeighbour = mesh_.faceNeighbour();
467 
468  const label nBoundaryFaces = mesh_.nBoundaryFaces();
469 
470  // Calculate face size from cell volumes for internal faces
471  for (label intFacei = 0; intFacei < mesh_.nInternalFaces(); ++intFacei)
472  {
473  const scalar cellOwnerVol = max(0.0, V[cellOwner[intFacei]]);
474  const scalar cellNeighbourVol = max(0.0, V[cellNeighbour[intFacei]]);
475 
476  scalar targetFaceSizeA = Foam::cbrt(cellOwnerVol);
477  scalar targetFaceSizeB = Foam::cbrt(cellNeighbourVol);
478 
479  targetFaceSizes[intFacei] = 0.5*(targetFaceSizeA + targetFaceSizeB);
480  }
481 
482  scalarField neiCellVolumes(nBoundaryFaces, -1);
483 
484  // Now do boundary faces
485  forAll(patches, patchi)
486  {
487  const polyPatch& patch = patches[patchi];
488 
489  label bFacei = patch.start() - mesh_.nInternalFaces();
490 
491  if (patch.coupled())
492  {
493  // Processor boundary face: Need to get the cell volume on the other
494  // processor
495  const labelUList& faceCells = patch.faceCells();
496 
497  forAll(faceCells, facei)
498  {
499  neiCellVolumes[bFacei++] = max(0.0, V[faceCells[facei]]);
500  }
501  }
502  else
503  {
504  // Normal boundary face: Just use owner cell volume to calculate
505  // the target face size
506  forAll(patch, patchFacei)
507  {
508  const label extFacei = patchFacei + patch.start();
509  const scalar cellOwnerVol = max(0.0, V[cellOwner[extFacei]]);
510 
511  targetFaceSizes[extFacei] = Foam::cbrt(cellOwnerVol);
512  }
513  }
514  }
515 
516  syncTools::swapBoundaryFaceList(mesh_, neiCellVolumes);
517 
518  forAll(patches, patchi)
519  {
520  const polyPatch& patch = patches[patchi];
521 
522  label bFacei = patch.start() - mesh_.nInternalFaces();
523 
524  if (patch.coupled())
525  {
526  forAll(patch, patchFacei)
527  {
528  const label localFacei = patchFacei + patch.start();
529  const scalar cellOwnerVol = max(0.0, V[cellOwner[localFacei]]);
530  const scalar cellNeighbourVol = neiCellVolumes[bFacei++];
531 
532  scalar targetFaceSizeA = Foam::cbrt(cellOwnerVol);
533  scalar targetFaceSizeB = Foam::cbrt(cellNeighbourVol);
534 
535  targetFaceSizes[localFacei]
536  = 0.5*(targetFaceSizeA + targetFaceSizeB);
537  }
538  }
539  }
540 
541  // Returns a characteristic length, not an area
542  return targetFaceSizes;
543 }
544 
545 
546 Foam::edgeCollapser::collapseType Foam::edgeCollapser::collapseFace
547 (
548  const labelList& pointPriority,
549  const face& f,
550  const label facei,
551  const scalar targetFaceSize,
552  bitSet& collapseEdge,
553  Map<point>& collapsePointToLocation,
554  const scalarField& faceFilterFactor
555 ) const
556 {
557  const scalar collapseSizeLimitCoeff = faceFilterFactor[facei];
558 
559  const pointField& pts = mesh_.points();
560 
561  labelList facePts(f);
562 
563  const Foam::point fC = f.centre(pts);
564 
565  const scalar fA = f.mag(pts);
566 
567  vector collapseAxis = Zero;
568  scalar aspectRatio = 1.0;
569 
570  faceCollapseAxisAndAspectRatio(f, fC, collapseAxis, aspectRatio);
571 
572  // The signed distance along the collapse axis passing through the
573  // face centre that each vertex projects to.
574 
575  scalarField d(f.size());
576 
577  forAll(f, fPtI)
578  {
579  const Foam::point& pt = pts[f[fPtI]];
580 
581  d[fPtI] = (collapseAxis & (pt - fC));
582  }
583 
584  // Sort the projected distances and the corresponding vertex
585  // indices along the collapse axis
586 
587  labelList oldToNew(sortedOrder(d));
588 
589  oldToNew = invert(oldToNew.size(), oldToNew);
590 
591  inplaceReorder(oldToNew, d);
592 
593  inplaceReorder(oldToNew, facePts);
594 
595  // Shift the points so that they are relative to the centre of the
596  // collapse line.
597 
598  scalar dShift = -0.5*(d.first() + d.last());
599 
600  d += dShift;
601 
602  // Form two lists, one for each half of the set of points
603  // projected along the collapse axis.
604 
605  // Middle value, index of first entry in the second half
606  label middle = -1;
607 
608  forAll(d, dI)
609  {
610  if (d[dI] > 0)
611  {
612  middle = dI;
613 
614  break;
615  }
616  }
617 
618  if (middle == -1)
619  {
620 // SeriousErrorInFunction
621 // << "middle == -1, " << f << " " << d
622 // << endl;//abort(FatalError);
623 
624  return noCollapse;
625  }
626 
627  // Negative half
628  SubList<scalar> dNeg(d, middle, 0);
629  SubList<label> facePtsNeg(facePts, middle, 0);
630 
631  // Positive half
632  SubList<scalar> dPos(d, d.size() - middle, middle);
633  SubList<label> facePtsPos(facePts, d.size() - middle, middle);
634 
635  // Defining how close to the midpoint (M) of the projected
636  // vertices line a projected vertex (X) can be before making this
637  // an invalid edge collapse
638  //
639  // X---X-g----------------M----X-----------g----X--X
640  //
641  // Only allow a collapse if all projected vertices are outwith
642  // guardFraction (g) of the distance form the face centre to the
643  // furthest vertex in the considered direction
644 
645  if (dNeg.size() == 0 || dPos.size() == 0)
646  {
648  << "All points on one side of face centre, not collapsing."
649  << endl;
650  }
651 
652 // Info<< "Face : " << f << nl
653 // << " Collapse Axis: " << collapseAxis << nl
654 // << " Aspect Ratio : " << aspectRatio << endl;
655 
656  collapseType typeOfCollapse = noCollapse;
657 
658  if (magSqr(collapseAxis) < VSMALL)
659  {
660  typeOfCollapse = toPoint;
661  }
662  else if (fA < aspectRatio*sqr(targetFaceSize*collapseSizeLimitCoeff))
663  {
664  if
665  (
666  allowEarlyCollapseToPoint_
667  && (d.last() - d.first())
668  < targetFaceSize
669  *allowEarlyCollapseCoeff_*maxCollapseFaceToPointSideLengthCoeff_
670  )
671  {
672  typeOfCollapse = toPoint;
673  }
674  else if
675  (
676  (dNeg.last() < guardFraction_*dNeg.first())
677  && (dPos.first() > guardFraction_*dPos.last())
678  )
679  {
680  typeOfCollapse = toEdge;
681  }
682  else if
683  (
684  (d.last() - d.first())
685  < targetFaceSize
686  *maxCollapseFaceToPointSideLengthCoeff_
687  )
688  {
689  // If the face can't be collapsed to an edge, and it has a
690  // small enough span, collapse it to a point.
691  typeOfCollapse = toPoint;
692  }
693  }
694 
695  if (typeOfCollapse == toPoint)
696  {
697  collapseToPoint
698  (
699  facei,
700  pts,
701  pointPriority,
702  fC,
703  facePts,
704  collapseEdge,
705  collapsePointToLocation
706  );
707  }
708  else if (typeOfCollapse == toEdge)
709  {
710  collapseToEdge
711  (
712  facei,
713  pts,
714  pointPriority,
715  collapseAxis,
716  fC,
717  facePtsNeg,
718  facePtsPos,
719  dNeg,
720  dPos,
721  dShift,
722  collapseEdge,
723  collapsePointToLocation
724  );
725  }
726 
727  return typeOfCollapse;
728 }
729 
730 
731 Foam::label Foam::edgeCollapser::edgeMaster
732 (
733  const labelList& pointPriority,
734  const edge& e
735 ) const
736 {
737  label masterPoint = -1;
738 
739  const label e0 = e.start();
740  const label e1 = e.end();
741 
742  const label e0Priority = pointPriority[e0];
743  const label e1Priority = pointPriority[e1];
744 
745  if (e0Priority > e1Priority)
746  {
747  masterPoint = e0;
748  }
749  else if (e0Priority < e1Priority)
750  {
751  masterPoint = e1;
752  }
753  else if (e0Priority == e1Priority)
754  {
755  masterPoint = e0;
756  }
757 
758 // // Collapse edge to point with higher priority.
759 // if (pointPriority[e0] >= 0)
760 // {
761 // if (pointPriority[e1] >= 0)
762 // {
763 // // Both points have high priority. Choose one to collapse to.
764 // // Note: should look at feature edges/points!
765 // masterPoint = e0;
766 // }
767 // else
768 // {
769 // masterPoint = e0;
770 // }
771 // }
772 // else
773 // {
774 // if (pointPriority[e1] >= 0)
775 // {
776 // masterPoint = e1;
777 // }
778 // else
779 // {
780 // // None on boundary. Neither is a master.
781 // return -1;
782 // }
783 // }
784 
785  return masterPoint;
786 }
787 
788 
789 void Foam::edgeCollapser::checkBoundaryPointMergeEdges
790 (
791  const label pointi,
792  const label otherPointi,
793  const labelList& pointPriority,
794  Map<point>& collapsePointToLocation
795 ) const
796 {
797  const pointField& points = mesh_.points();
798 
799  const label e0Priority = pointPriority[pointi];
800  const label e1Priority = pointPriority[otherPointi];
801 
802  if (e0Priority > e1Priority)
803  {
804  collapsePointToLocation.set
805  (
806  otherPointi,
807  points[pointi]
808  );
809  }
810  else if (e0Priority < e1Priority)
811  {
812  collapsePointToLocation.set
813  (
814  pointi,
815  points[otherPointi]
816  );
817  }
818  else // e0Priority == e1Priority
819  {
820  collapsePointToLocation.set
821  (
822  pointi,
823  points[otherPointi]
824  );
825 
826 // Foam::point averagePt
827 // (
828 // 0.5*(points[otherPointi] + points[pointi])
829 // );
830 //
831 // collapsePointToLocation.set(pointi, averagePt);
832 // collapsePointToLocation.set(otherPointi, averagePt);
833  }
834 }
835 
836 
837 Foam::label Foam::edgeCollapser::breakStringsAtEdges
838 (
839  const bitSet& markedEdges,
840  bitSet& collapseEdge,
841  List<pointEdgeCollapse>& allPointInfo
842 ) const
843 {
844  const edgeList& edges = mesh_.edges();
845  const labelListList& pointEdges = mesh_.pointEdges();
846 
847  label nUncollapsed = 0;
848 
849  forAll(edges, eI)
850  {
851  if (markedEdges.test(eI))
852  {
853  const edge& e = edges[eI];
854 
855  const label startCollapseIndex
856  = allPointInfo[e.start()].collapseIndex();
857 
858  if (startCollapseIndex != -1 && startCollapseIndex != -2)
859  {
860  const label endCollapseIndex
861  = allPointInfo[e.end()].collapseIndex();
862 
863  if
864  (
865  !collapseEdge.test(eI)
866  && startCollapseIndex == endCollapseIndex
867  )
868  {
869  const labelList& ptEdgesStart = pointEdges[e.start()];
870 
871  forAll(ptEdgesStart, ptEdgeI)
872  {
873  const label edgeI = ptEdgesStart[ptEdgeI];
874 
875  const label nbrPointi
876  = edges[edgeI].otherVertex(e.start());
877  const label nbrIndex
878  = allPointInfo[nbrPointi].collapseIndex();
879 
880  if
881  (
882  nbrIndex == startCollapseIndex
883  && collapseEdge.test(edgeI)
884  )
885  {
886  collapseEdge.unset(edgeI);
887  nUncollapsed++;
888  }
889  }
890  }
891  }
892  }
893  }
894 
895  return nUncollapsed;
896 }
897 
898 
899 void Foam::edgeCollapser::determineDuplicatePointsOnFace
900 (
901  const face& f,
902  bitSet& markedPoints,
903  labelHashSet& uniqueCollapses,
904  labelHashSet& duplicateCollapses,
905  List<pointEdgeCollapse>& allPointInfo
906 ) const
907 {
908  uniqueCollapses.clear();
909  duplicateCollapses.clear();
910 
911  forAll(f, fpI)
912  {
913  label index = allPointInfo[f[fpI]].collapseIndex();
914 
915  // Check for consecutive duplicate
916  if (index != allPointInfo[f.prevLabel(fpI)].collapseIndex())
917  {
918  if (!uniqueCollapses.insert(index))
919  {
920  // Failed inserting so duplicate
921  duplicateCollapses.insert(index);
922  }
923  }
924  }
925 
926  // Now duplicateCollapses contains duplicate collapse indices.
927  // Convert to points.
928  forAll(f, fpI)
929  {
930  label index = allPointInfo[f[fpI]].collapseIndex();
931  if (duplicateCollapses.found(index))
932  {
933  markedPoints.set(f[fpI]);
934  }
935  }
936 }
937 
938 
939 Foam::label Foam::edgeCollapser::countEdgesOnFace
940 (
941  const face& f,
942  List<pointEdgeCollapse>& allPointInfo
943 ) const
944 {
945  label nEdges = 0;
946 
947  forAll(f, fpI)
948  {
949  const label pointi = f[fpI];
950  const label newPointi = allPointInfo[pointi].collapseIndex();
951 
952  if (newPointi == -2)
953  {
954  nEdges++;
955  }
956  else
957  {
958  const label prevPointi = f[f.fcIndex(fpI)];
959  const label prevNewPointi
960  = allPointInfo[prevPointi].collapseIndex();
961 
962  if (newPointi != prevNewPointi)
963  {
964  nEdges++;
965  }
966  }
967  }
968 
969  return nEdges;
970 }
971 
972 
973 bool Foam::edgeCollapser::isFaceCollapsed
974 (
975  const face& f,
976  List<pointEdgeCollapse>& allPointInfo
977 ) const
978 {
979  label nEdges = countEdgesOnFace(f, allPointInfo);
980 
981  // Polygons must have 3 or more edges to be valid
982  if (nEdges < 3)
983  {
984  return true;
985  }
986 
987  return false;
988 }
989 
990 
991 // Create consistent set of collapses.
992 // collapseEdge : per edge:
993 // -1 : do not collapse
994 // 0 : collapse to start
995 // 1 : collapse to end
996 // Note: collapseEdge has to be parallel consistent (in orientation)
997 Foam::label Foam::edgeCollapser::syncCollapse
998 (
999  const globalIndex& globalPoints,
1000  const labelList& pointPriority,
1001  const bitSet& collapseEdge,
1002  const Map<point>& collapsePointToLocation,
1003  List<pointEdgeCollapse>& allPointInfo
1004 ) const
1005 {
1006  const edgeList& edges = mesh_.edges();
1007 
1008  label nCollapsed = 0;
1009 
1010  DynamicList<label> initPoints(mesh_.nPoints());
1011  DynamicList<pointEdgeCollapse> initPointInfo(mesh_.nPoints());
1012 
1013  allPointInfo.clear();
1014  allPointInfo.setSize(mesh_.nPoints());
1015 
1016  // Initialise edges to no collapse
1017  List<pointEdgeCollapse> allEdgeInfo
1018  (
1019  mesh_.nEdges(),
1020  pointEdgeCollapse(Zero, -1, -1)
1021  );
1022 
1023  // Mark selected edges for collapse
1024  forAll(edges, edgeI)
1025  {
1026  if (collapseEdge[edgeI])
1027  {
1028  const edge& e = edges[edgeI];
1029 
1030  label masterPointi = e.start();
1031 
1032  // Choose the point on the edge with the highest priority.
1033  if (pointPriority[e.end()] > pointPriority[e.start()])
1034  {
1035  masterPointi = e.end();
1036  }
1037 
1038  label masterPointPriority = pointPriority[masterPointi];
1039 
1040  label index = globalPoints.toGlobal(masterPointi);
1041 
1042  if (!collapsePointToLocation.found(masterPointi))
1043  {
1044  const label otherVertex = e.otherVertex(masterPointi);
1045 
1046  if (!collapsePointToLocation.found(otherVertex))
1047  {
1049  << masterPointi << " on edge " << edgeI << " " << e
1050  << " is not marked for collapse."
1051  << abort(FatalError);
1052  }
1053  else
1054  {
1055  masterPointi = otherVertex;
1056  masterPointPriority = pointPriority[masterPointi];
1057  index = globalPoints.toGlobal(masterPointi);
1058  }
1059  }
1060 
1061  const point& collapsePoint = collapsePointToLocation[masterPointi];
1062 
1063  const pointEdgeCollapse pec
1064  (
1065  collapsePoint,
1066  index,
1067  masterPointPriority
1068  );
1069 
1070  // Mark as collapsible but with nonsense master so it gets
1071  // overwritten and starts an update wave
1072  allEdgeInfo[edgeI] = pointEdgeCollapse
1073  (
1074  collapsePoint,
1075  labelMax,
1076  labelMin
1077  );
1078 
1079  initPointInfo.append(pec);
1080  initPoints.append(e.start());
1081 
1082  initPointInfo.append(pec);
1083  initPoints.append(e.end());
1084 
1085  nCollapsed++;
1086  }
1087  }
1088 
1089  PointEdgeWave<pointEdgeCollapse> collapsePropagator
1090  (
1091  mesh_,
1092  initPoints,
1093  initPointInfo,
1094  allPointInfo,
1095  allEdgeInfo,
1096  mesh_.globalData().nTotalPoints() // Maximum number of iterations
1097  );
1098 
1099  return nCollapsed;
1100 }
1101 
1102 
1103 void Foam::edgeCollapser::filterFace
1104 (
1105  const Map<DynamicList<label>>& collapseStrings,
1106  const List<pointEdgeCollapse>& allPointInfo,
1107  face& f
1108 ) const
1109 {
1110  label newFp = 0;
1111 
1112  face oldFace = f;
1113 
1114  forAll(f, fp)
1115  {
1116  label pointi = f[fp];
1117 
1118  label collapseIndex = allPointInfo[pointi].collapseIndex();
1119 
1120  // Do we have a local point for this index?
1121  if (collapseStrings.found(collapseIndex))
1122  {
1123  const label localPointi = collapseStrings[collapseIndex][0];
1124 
1125  if (!SubList<label>(f, newFp).found(localPointi))
1126  {
1127  f[newFp++] = localPointi;
1128  }
1129  }
1130  else if (collapseIndex == -1)
1131  {
1133  << "Point " << pointi << " was not visited by PointEdgeWave"
1134  << endl;
1135  }
1136  else
1137  {
1138  f[newFp++] = pointi;
1139  }
1140  }
1141 
1142 
1143  // Check for pinched face. Tries to correct
1144  // - consecutive duplicate vertex. Removes duplicate vertex.
1145  // - duplicate vertex with one other vertex in between (spike).
1146  // Both of these should not really occur! and should be checked before
1147  // collapsing edges.
1148 
1149  const label size = newFp;
1150 
1151  newFp = 2;
1152 
1153  for (label fp = 2; fp < size; fp++)
1154  {
1155  label fp1 = fp-1;
1156  label fp2 = fp-2;
1157 
1158  label pointi = f[fp];
1159 
1160  // Search for previous occurrence.
1161  const label index = SubList<label>(f, fp).find(pointi);
1162 
1163  if (index == fp1)
1164  {
1166  << "Removing consecutive duplicate vertex in face "
1167  << f << endl;
1168  // Don't store current pointi
1169  }
1170  else if (index == fp2)
1171  {
1173  << "Removing non-consecutive duplicate vertex in face "
1174  << f << endl;
1175  // Don't store current pointi and remove previous
1176  newFp--;
1177  }
1178  else if (index != -1)
1179  {
1181  << "Pinched face " << f << endl;
1182  f[newFp++] = pointi;
1183  }
1184  else
1185  {
1186  f[newFp++] = pointi;
1187  }
1188  }
1189 
1190  f.setSize(newFp);
1191 }
1192 
1193 
1194 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1195 
1196 Foam::edgeCollapser::edgeCollapser(const polyMesh& mesh)
1197 :
1198  mesh_(mesh),
1199  guardFraction_(0),
1200  maxCollapseFaceToPointSideLengthCoeff_(0),
1201  allowEarlyCollapseToPoint_(false),
1202  allowEarlyCollapseCoeff_(0)
1203 {}
1204 
1205 
1206 Foam::edgeCollapser::edgeCollapser
1208  const polyMesh& mesh,
1209  const dictionary& dict
1210 )
1211 :
1212  mesh_(mesh),
1213  guardFraction_
1214  (
1215  dict.getOrDefault<scalar>("guardFraction", 0)
1216  ),
1217  maxCollapseFaceToPointSideLengthCoeff_
1218  (
1219  dict.getOrDefault<scalar>("maxCollapseFaceToPointSideLengthCoeff", 0)
1220  ),
1221  allowEarlyCollapseToPoint_
1222  (
1223  dict.getOrDefault("allowEarlyCollapseToPoint", true)
1224  ),
1225  allowEarlyCollapseCoeff_
1226  (
1227  dict.getOrDefault<scalar>("allowEarlyCollapseCoeff", 0)
1228  )
1229 {
1230  if (debug)
1231  {
1232  Info<< "Edge Collapser Settings:" << nl
1233  << " Guard Fraction = " << guardFraction_ << nl
1234  << " Max collapse face to point side length = "
1235  << maxCollapseFaceToPointSideLengthCoeff_ << nl
1236  << " " << (allowEarlyCollapseToPoint_ ? "Allow" : "Do not allow")
1237  << " early collapse to point" << nl
1238  << " Early collapse coeff = " << allowEarlyCollapseCoeff_
1239  << endl;
1240  }
1241 }
1242 
1243 
1244 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1245 
1248  const List<pointEdgeCollapse>& allPointInfo,
1249  polyTopoChange& meshMod
1250 ) const
1251 {
1252  const cellList& cells = mesh_.cells();
1253  const labelList& faceOwner = mesh_.faceOwner();
1254  const labelList& faceNeighbour = mesh_.faceNeighbour();
1255  const labelListList& pointFaces = mesh_.pointFaces();
1256  const pointZoneMesh& pointZones = mesh_.pointZones();
1257 
1258 
1259 
1260 
1261 // // Dump point collapses
1262 // label count = 0;
1263 // forAll(allPointInfo, ptI)
1264 // {
1265 // const pointEdgeCollapse& pec = allPointInfo[ptI];
1266 //
1267 // if (mesh_.points()[ptI] != pec.collapsePoint())
1268 // {
1269 // count++;
1270 // }
1271 // }
1272 //
1273 // OFstream str("collapses_" + name(count) + ".obj");
1274 // // Dump point collapses
1275 // forAll(allPointInfo, ptI)
1276 // {
1277 // const pointEdgeCollapse& pec = allPointInfo[ptI];
1278 //
1279 // if
1280 // (
1281 // mesh_.points()[ptI] != pec.collapsePoint()
1282 // && pec.collapsePoint() != vector(GREAT, GREAT, GREAT)
1283 // )
1284 // {
1285 // meshTools::writeOBJ
1286 // (
1287 // str,
1288 // mesh_.points()[ptI],
1289 // pec.collapsePoint()
1290 // );
1291 // }
1292 // }
1293 
1294 
1295 
1296  bool meshChanged = false;
1297 
1298  bitSet removedPoints(mesh_.nPoints());
1299 
1300  // Create strings of edges.
1301  // Map from collapseIndex(=global master point) to set of points
1302  Map<DynamicList<label>> collapseStrings;
1303  {
1304  // 1. Count elements per collapseIndex
1305  Map<label> nPerIndex(mesh_.nPoints()/10);
1306  forAll(allPointInfo, pointi)
1307  {
1308  label collapseIndex = allPointInfo[pointi].collapseIndex();
1309 
1310  if (collapseIndex != -1 && collapseIndex != -2)
1311  {
1312  ++(nPerIndex(collapseIndex, 0));
1313  }
1314  }
1315 
1316  // 2. Size
1317  collapseStrings.resize(2*nPerIndex.size());
1318  forAllConstIters(nPerIndex, iter)
1319  {
1320  collapseStrings.insert(iter.key(), DynamicList<label>(iter.val()));
1321  }
1322 
1323  // 3. Fill
1324  forAll(allPointInfo, pointi)
1325  {
1326  const label collapseIndex = allPointInfo[pointi].collapseIndex();
1327 
1328  if (collapseIndex != -1 && collapseIndex != -2)
1329  {
1330  collapseStrings[collapseIndex].append(pointi);
1331  }
1332  }
1333  }
1334 
1335 
1336 
1337 
1338 // OFstream str2("collapseStrings_" + name(count) + ".obj");
1339 // // Dump point collapses
1340 // forAllConstIters(collapseStrings, iter)
1341 // {
1342 // const label masterPoint = iter.key();
1343 // const DynamicList<label>& edgeCollapses = iter();
1344 //
1345 // forAll(edgeCollapses, eI)
1346 // {
1347 // meshTools::writeOBJ
1348 // (
1349 // str2,
1350 // mesh_.points()[edgeCollapses[eI]],
1351 // mesh_.points()[masterPoint]
1352 // );
1353 // }
1354 // }
1355 
1356 
1357 
1358  // Current faces (is also collapseStatus: f.size() < 3)
1359  faceList newFaces(mesh_.faces());
1360 
1361  // Current cellCollapse status
1362  bitSet cellRemoved(mesh_.nCells(), false);
1363 
1364  label nUnvisited = 0;
1365  label nUncollapsed = 0;
1366  label nCollapsed = 0;
1367 
1368  forAll(allPointInfo, pI)
1369  {
1370  const pointEdgeCollapse& pec = allPointInfo[pI];
1371 
1372  if (pec.collapseIndex() == -1)
1373  {
1374  nUnvisited++;
1375  }
1376  else if (pec.collapseIndex() == -2)
1377  {
1378  nUncollapsed++;
1379  }
1380  else
1381  {
1382  nCollapsed++;
1383  }
1384  }
1385 
1386  label nPoints = allPointInfo.size();
1387 
1389  reduce(nUnvisited, sumOp<label>());
1390  reduce(nUncollapsed, sumOp<label>());
1391  reduce(nCollapsed, sumOp<label>());
1392 
1393  Info<< incrIndent;
1394  Info<< indent << "Number of points : " << nPoints << nl
1395  << indent << "Not visited : " << nUnvisited << nl
1396  << indent << "Not collapsed : " << nUncollapsed << nl
1397  << indent << "Collapsed : " << nCollapsed << nl
1398  << endl;
1399  Info<< decrIndent;
1400 
1401  do
1402  {
1403  forAll(newFaces, facei)
1404  {
1405  filterFace(collapseStrings, allPointInfo, newFaces[facei]);
1406  }
1407 
1408  // Check if faces to be collapsed cause cells to become collapsed.
1409  label nCellCollapsed = 0;
1410 
1411  forAll(cells, celli)
1412  {
1413  if (!cellRemoved.test(celli))
1414  {
1415  const cell& cFaces = cells[celli];
1416 
1417  label nFaces = cFaces.size();
1418 
1419  forAll(cFaces, i)
1420  {
1421  label facei = cFaces[i];
1422 
1423  if (newFaces[facei].size() < 3)
1424  {
1425  --nFaces;
1426 
1427  if (nFaces < 4)
1428  {
1429  Pout<< "Cell:" << celli
1430  << " uses faces:" << cFaces
1431  << " of which too many are marked for removal:"
1432  << endl
1433  << " ";
1434 
1435 
1436  forAll(cFaces, j)
1437  {
1438  if (newFaces[cFaces[j]].size() < 3)
1439  {
1440  Pout<< ' '<< cFaces[j];
1441  }
1442  }
1443  Pout<< endl;
1444 
1445  cellRemoved.set(celli);
1446 
1447  // Collapse all edges of cell to nothing
1448 // collapseEdges(cellEdges[celli]);
1449 
1450  nCellCollapsed++;
1451 
1452  break;
1453  }
1454  }
1455  }
1456  }
1457  }
1458 
1459  reduce(nCellCollapsed, sumOp<label>());
1460  Info<< indent << "Collapsing " << nCellCollapsed << " cells" << endl;
1461 
1462  if (nCellCollapsed == 0)
1463  {
1464  break;
1465  }
1466 
1467  } while (true);
1468 
1469 
1470  // Keep track of faces that have been done already.
1471  bitSet doneFace(mesh_.nFaces(), false);
1472 
1473  {
1474  // Mark points used.
1475  bitSet usedPoint(mesh_.nPoints(), false);
1476 
1477  forAll(cellRemoved, celli)
1478  {
1479  if (cellRemoved.test(celli))
1480  {
1481  meshMod.removeCell(celli, -1);
1482  }
1483  }
1484 
1485  // Remove faces
1486  forAll(newFaces, facei)
1487  {
1488  const face& f = newFaces[facei];
1489 
1490  if (f.size() < 3)
1491  {
1492  meshMod.removeFace(facei, -1);
1493  meshChanged = true;
1494 
1495  // Mark face as been done - i.e. ignore it later
1496  doneFace.set(facei);
1497  }
1498  else
1499  {
1500  // Kept face. Mark vertices
1501  usedPoint.set(f);
1502  }
1503  }
1504 
1505  // Remove unused vertices that have not been marked for removal already
1506  forAll(usedPoint, pointi)
1507  {
1508  if (!usedPoint.test(pointi))
1509  {
1510  removedPoints.set(pointi);
1511  meshMod.removePoint(pointi, -1);
1512  meshChanged = true;
1513  }
1514  }
1515  }
1516 
1517  // Modify the point location of the remaining points
1518  forAll(allPointInfo, pointi)
1519  {
1520  const label collapseIndex = allPointInfo[pointi].collapseIndex();
1521  const point& collapsePoint = allPointInfo[pointi].collapsePoint();
1522 
1523  if
1524  (
1525  !removedPoints.test(pointi)
1526  && collapseIndex != -1
1527  && collapseIndex != -2
1528  )
1529  {
1530  meshMod.modifyPoint
1531  (
1532  pointi,
1533  collapsePoint,
1534  pointZones.whichZone(pointi),
1535  false
1536  );
1537  }
1538  }
1539 
1540 
1541  const polyBoundaryMesh& boundaryMesh = mesh_.boundaryMesh();
1542  const faceZoneMesh& faceZones = mesh_.faceZones();
1543 
1544  // Renumber faces that use points
1545  forAll(allPointInfo, pointi)
1546  {
1547  if (removedPoints.test(pointi))
1548  {
1549  const labelList& changedFaces = pointFaces[pointi];
1550 
1551  forAll(changedFaces, changedFacei)
1552  {
1553  label facei = changedFaces[changedFacei];
1554 
1555  if (doneFace.set(facei))
1556  {
1557  // On first visit...
1558 
1559  // Get current zone info
1560  label zoneID = faceZones.whichZone(facei);
1561 
1562  bool zoneFlip = false;
1563 
1564  if (zoneID >= 0)
1565  {
1566  const faceZone& fZone = faceZones[zoneID];
1567 
1568  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
1569  }
1570 
1571  // Get current connectivity
1572  label own = faceOwner[facei];
1573  label nei = -1;
1574  label patchID = -1;
1575 
1576  if (mesh_.isInternalFace(facei))
1577  {
1578  nei = faceNeighbour[facei];
1579  }
1580  else
1581  {
1582  patchID = boundaryMesh.whichPatch(facei);
1583  }
1584 
1585  meshMod.modifyFace
1586  (
1587  newFaces[facei], // face
1588  facei, // facei to change
1589  own, // owner
1590  nei, // neighbour
1591  false, // flipFaceFlux
1592  patchID, // patch
1593  zoneID,
1594  zoneFlip
1595  );
1596 
1597  meshChanged = true;
1598  }
1599  }
1600  }
1601  }
1602 
1603  return meshChanged;
1604 }
1605 
1606 
1609  const globalIndex& globalPoints,
1610  const labelList& pointPriority,
1611  const Map<point>& collapsePointToLocation,
1613  List<pointEdgeCollapse>& allPointInfo,
1614  const bool allowCellCollapse
1615 ) const
1616 {
1617  // Make sure we don't collapse cells
1618  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1619  const faceList faces = mesh_.faces();
1620  const edgeList& edges = mesh_.edges();
1621  const labelListList& faceEdges = mesh_.faceEdges();
1622  const labelListList& pointEdges = mesh_.pointEdges();
1623  const cellList& cells = mesh_.cells();
1624 
1625  labelHashSet uniqueCollapses;
1626  labelHashSet duplicateCollapses;
1627 
1628  while (true)
1629  {
1630  label nUncollapsed = 0;
1631 
1633  (
1634  mesh_,
1635  collapseEdge,
1637  0
1638  );
1639 
1640  // Create consistent set of collapses
1641  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1642  // Note: requires collapseEdge to be synchronised.
1643  syncCollapse
1644  (
1645  globalPoints,
1646  pointPriority,
1647  collapseEdge,
1648  collapsePointToLocation,
1649  allPointInfo
1650  );
1651 
1652  // Get collapsed faces
1653 
1654  bitSet isCollapsedFace(mesh_.nFaces());
1655  bitSet markedPoints(mesh_.nPoints());
1656 
1657  forAll(faces, facei)
1658  {
1659  const face& f = faces[facei];
1660 
1661  isCollapsedFace[facei] = isFaceCollapsed(f, allPointInfo);
1662 
1663  if (!isCollapsedFace.test(facei))
1664  {
1665  determineDuplicatePointsOnFace
1666  (
1667  f,
1668  markedPoints,
1669  uniqueCollapses,
1670  duplicateCollapses,
1671  allPointInfo
1672  );
1673  }
1674  }
1675 
1676  // Synchronise the marked points
1678  (
1679  mesh_,
1680  markedPoints,
1682  0
1683  );
1684 
1685  // Mark all edges attached to the point for collapse
1686  forAll(markedPoints, pointi)
1687  {
1688  if (markedPoints.test(pointi))
1689  {
1690  const label index = allPointInfo[pointi].collapseIndex();
1691 
1692  const labelList& ptEdges = pointEdges[pointi];
1693 
1694  forAll(ptEdges, ptEdgeI)
1695  {
1696  const label edgeI = ptEdges[ptEdgeI];
1697  const label nbrPointi = edges[edgeI].otherVertex(pointi);
1698  const label nbrIndex
1699  = allPointInfo[nbrPointi].collapseIndex();
1700 
1701  if (nbrIndex == index && collapseEdge.test(edgeI))
1702  {
1703  collapseEdge.unset(edgeI);
1704  nUncollapsed++;
1705  }
1706  }
1707  }
1708  }
1709 
1710  bitSet markedEdges(mesh_.nEdges());
1711 
1712  if (!allowCellCollapse)
1713  {
1714  // Check collapsed cells
1715  forAll(cells, celli)
1716  {
1717  const cell& cFaces = cells[celli];
1718 
1719  label nFaces = cFaces.size();
1720 
1721  forAll(cFaces, fI)
1722  {
1723  label facei = cFaces[fI];
1724 
1725  if (isCollapsedFace.test(facei))
1726  {
1727  --nFaces;
1728  }
1729  }
1730 
1731  if (nFaces < 4)
1732  {
1733  forAll(cFaces, fI)
1734  {
1735  label facei = cFaces[fI];
1736 
1737  const labelList& fEdges = faceEdges[facei];
1738 
1739  // Unmark this face for collapse
1740  forAll(fEdges, fEdgeI)
1741  {
1742  label edgeI = fEdges[fEdgeI];
1743 
1744  if (collapseEdge.unset(edgeI))
1745  {
1746  ++nUncollapsed;
1747  }
1748 
1749  markedEdges.set(edgeI);
1750  }
1751 
1752  // Uncollapsed this face.
1753  isCollapsedFace.unset(facei);
1754  ++nFaces;
1755  }
1756  }
1757 
1758  if (nFaces < 4)
1759  {
1761  << "Cell " << celli << " " << cFaces << nl
1762  << "is " << nFaces << ", "
1763  << "but cell collapse has been disabled."
1764  << abort(FatalError);
1765  }
1766  }
1767  }
1768 
1770  (
1771  mesh_,
1772  markedEdges,
1774  0
1775  );
1776 
1777  nUncollapsed += breakStringsAtEdges
1778  (
1779  markedEdges,
1780  collapseEdge,
1781  allPointInfo
1782  );
1783 
1784  reduce(nUncollapsed, sumOp<label>());
1785 
1786  Info<< " Uncollapsed edges = " << nUncollapsed << " / "
1787  << returnReduce(mesh_.nEdges(), sumOp<label>()) << endl;
1788 
1789  if (nUncollapsed == 0)
1790  {
1791  break;
1792  }
1793  }
1794 }
1795 
1796 
1799  const scalarField& minEdgeLen,
1800  const labelList& pointPriority,
1802  Map<point>& collapsePointToLocation
1803 ) const
1804 {
1805  // Work out which edges to collapse
1806  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1807 
1808  const pointField& points = mesh_.points();
1809  const edgeList& edges = mesh_.edges();
1810 
1811  label nCollapsed = 0;
1812 
1813  forAll(edges, edgeI)
1814  {
1815  const edge& e = edges[edgeI];
1816 
1817  if (!collapseEdge.test(edgeI))
1818  {
1819  if (e.mag(points) < minEdgeLen[edgeI])
1820  {
1821  collapseEdge.set(edgeI);
1822 
1823  label masterPointi = edgeMaster(pointPriority, e);
1824 
1825  if (masterPointi == -1)
1826  {
1827  const point average
1828  = 0.5*(points[e.start()] + points[e.end()]);
1829 
1830  collapsePointToLocation.set(e.start(), average);
1831  }
1832  else
1833  {
1834  const point& collapsePt = points[masterPointi];
1835 
1836  collapsePointToLocation.set(masterPointi, collapsePt);
1837  }
1838 
1839  nCollapsed++;
1840  }
1841  }
1842  }
1843 
1844  return nCollapsed;
1845 }
1846 
1847 
1850  const scalar maxCos,
1851  const labelList& pointPriority,
1853  Map<point>& collapsePointToLocation
1854 ) const
1855 {
1856  const edgeList& edges = mesh_.edges();
1857  const pointField& points = mesh_.points();
1858  const labelListList& pointEdges = mesh_.pointEdges();
1859 
1860  // Point removal engine
1861  removePoints pointRemover(mesh_, false);
1862 
1863  // Find out points that can be deleted
1864  boolList pointCanBeDeleted;
1865  label nTotRemove = pointRemover.countPointUsage(maxCos, pointCanBeDeleted);
1866 
1867  // Rework point-to-remove into edge-to-collapse.
1868 
1869  label nCollapsed = 0;
1870 
1871  if (nTotRemove > 0)
1872  {
1873  forAll(pointEdges, pointi)
1874  {
1875  if (pointCanBeDeleted[pointi])
1876  {
1877  const labelList& pEdges = pointEdges[pointi];
1878 
1879  if (pEdges.size() == 2)
1880  {
1881  // Always the case?
1882 
1883  label e0 = pEdges[0];
1884  label e1 = pEdges[1];
1885 
1886  if (!collapseEdge[e0] && !collapseEdge[e1])
1887  {
1888  // Get lengths of both edges and choose the smallest
1889  scalar e0length = mag
1890  (
1891  points[edges[e0][0]] - points[edges[e0][1]]
1892  );
1893 
1894  scalar e1length = mag
1895  (
1896  points[edges[e1][0]] - points[edges[e1][1]]
1897  );
1898 
1899  if (e0length <= e1length)
1900  {
1901  collapseEdge.set(e0);
1902 
1903  checkBoundaryPointMergeEdges
1904  (
1905  pointi,
1906  edges[e0].otherVertex(pointi),
1907  pointPriority,
1908  collapsePointToLocation
1909  );
1910  }
1911  else
1912  {
1913  collapseEdge.set(e1);
1914 
1915  checkBoundaryPointMergeEdges
1916  (
1917  pointi,
1918  edges[e1].otherVertex(pointi),
1919  pointPriority,
1920  collapsePointToLocation
1921  );
1922  }
1923 
1924  nCollapsed++;
1925  }
1926  }
1927  }
1928  }
1929  }
1930 
1931  return nCollapsed;
1932 }
1933 
1934 
1937  const scalarField& faceFilterFactor,
1938  const labelList& pointPriority,
1940  Map<point>& collapsePointToLocation
1941 ) const
1942 {
1943  const faceList& faces = mesh_.faces();
1944 
1945  const scalarField targetFaceSizes = calcTargetFaceSizes();
1946 
1947  // Calculate number of faces that will be collapsed to a point or an edge
1948  label nCollapseToPoint = 0;
1949  label nCollapseToEdge = 0;
1950 
1951  forAll(faces, fI)
1952  {
1953  const face& f = faces[fI];
1954 
1955  if (faceFilterFactor[fI] <= 0)
1956  {
1957  continue;
1958  }
1959 
1960  collapseType flagCollapseFace = collapseFace
1961  (
1962  pointPriority,
1963  f,
1964  fI,
1965  targetFaceSizes[fI],
1966  collapseEdge,
1967  collapsePointToLocation,
1968  faceFilterFactor
1969  );
1970 
1971  if (flagCollapseFace == noCollapse)
1972  {
1973  continue;
1974  }
1975  else if (flagCollapseFace == toPoint)
1976  {
1977  nCollapseToPoint++;
1978  }
1979  else if (flagCollapseFace == toEdge)
1980  {
1981  nCollapseToEdge++;
1982  }
1983  else
1984  {
1986  << "Face is marked to be collapsed to " << flagCollapseFace
1987  << ". Currently can only collapse to point/edge."
1988  << abort(FatalError);
1989  }
1990  }
1991 
1992  return labelPair(nCollapseToPoint, nCollapseToEdge);
1993 }
1994 
1995 
1998  const faceZone& fZone,
1999  const scalarField& faceFilterFactor,
2000  const labelList& pointPriority,
2002  Map<point>& collapsePointToLocation
2003 ) const
2004 {
2005  const faceList& faces = mesh_.faces();
2006 
2007  const scalarField targetFaceSizes = calcTargetFaceSizes();
2008 
2009  // Calculate number of faces that will be collapsed to a point or an edge
2010  label nCollapseToPoint = 0;
2011  label nCollapseToEdge = 0;
2012 
2013  forAll(faces, fI)
2014  {
2015  if (fZone.whichFace(fI) == -1)
2016  {
2017  continue;
2018  }
2019 
2020  const face& f = faces[fI];
2021 
2022  if (faceFilterFactor[fI] <= 0)
2023  {
2024  continue;
2025  }
2026 
2027  collapseType flagCollapseFace = collapseFace
2028  (
2029  pointPriority,
2030  f,
2031  fI,
2032  targetFaceSizes[fI],
2033  collapseEdge,
2034  collapsePointToLocation,
2035  faceFilterFactor
2036  );
2037 
2038  if (flagCollapseFace == noCollapse)
2039  {
2040  continue;
2041  }
2042  else if (flagCollapseFace == toPoint)
2043  {
2044  nCollapseToPoint++;
2045  }
2046  else if (flagCollapseFace == toEdge)
2047  {
2048  nCollapseToEdge++;
2049  }
2050  else
2051  {
2053  << "Face is marked to be collapsed to " << flagCollapseFace
2054  << ". Currently can only collapse to point/edge."
2055  << abort(FatalError);
2056  }
2057  }
2058 
2059  return labelPair(nCollapseToPoint, nCollapseToEdge);
2060 
2061 // const edgeList& edges = mesh_.edges();
2062 // const pointField& points = mesh_.points();
2063 // const labelListList& edgeFaces = mesh_.edgeFaces();
2064 // const polyBoundaryMesh& bMesh = mesh_.boundaryMesh();
2065 //
2066 // forAll(edges, eI)
2067 // {
2068 // const edge& e = edges[eI];
2069 //
2070 // const labelList& eFaces = edgeFaces[eI];
2071 //
2072 // bool keepEdge = false;
2073 //
2074 // label nInternalFaces = 0;
2075 // label nPatchFaces = 0;
2076 // label nIndirectFaces = 0;
2077 //
2078 // bool coupled = false;
2079 //
2080 // forAll(eFaces, eFacei)
2081 // {
2082 // const label eFaceIndex = eFaces[eFacei];
2083 //
2084 // if (mesh_.isInternalFace(eFaceIndex))
2085 // {
2086 // nInternalFaces++;
2087 // }
2088 // else
2089 // {
2090 // const label patchIndex = bMesh.whichPatch(eFaceIndex);
2091 // const polyPatch& pPatch = bMesh[patchIndex];
2092 //
2093 // if (pPatch.coupled())
2094 // {
2095 // coupled = true;
2096 // nInternalFaces++;
2097 // }
2098 // else
2099 // {
2100 // // Keep the edge if an attached face is not in the zone
2101 // if (fZone.whichFace(eFaceIndex) == -1)
2102 // {
2103 // nPatchFaces++;
2104 // }
2105 // else
2106 // {
2107 // nIndirectFaces++;
2108 // }
2109 // }
2110 // }
2111 // }
2112 //
2113 // if (eFaces.size() != nInternalFaces + nPatchFaces + nIndirectFaces)
2114 // {
2115 // Pout<< eFaces.size() << " ("
2116 // << nInternalFaces << "/" << nPatchFaces << "/"
2117 // << nIndirectFaces << ")" << endl;
2118 // }
2119 //
2120 // if
2121 // (
2122 // eFaces.size() == nInternalFaces
2123 // || nIndirectFaces < (coupled ? 1 : 2)
2124 // )
2125 // {
2126 // keepEdge = true;
2127 // }
2128 //
2129 // if (!keepEdge)
2130 // {
2131 // collapseEdge.set(eI);
2132 //
2133 // const Foam::point collapsePoint =
2134 // 0.5*(points[e.end()] + points[e.start()]);
2135 //
2136 // collapsePointToLocation.insert(e.start(), collapsePoint);
2137 // collapsePointToLocation.insert(e.end(), collapsePoint);
2138 // }
2139 // }
2140 
2141 // OFstream str
2142 // (
2143 // mesh_.time().path()
2144 // /"markedEdges_" + name(collapseEdge.count()) + ".obj"
2145 // );
2146 // label count = 0;
2147 //
2148 // forAll(collapseEdge, eI)
2149 // {
2150 // if (collapseEdge.test(eI))
2151 // {
2152 // const edge& e = edges[eI];
2153 //
2154 // meshTools::writeOBJ
2155 // (
2156 // str,
2157 // points[e.start()],
2158 // points[e.end()],
2159 // count
2160 // );
2161 // }
2162 // }
2163 }
2164 
2165 
2166 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
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::HashTable::size
label size() const noexcept
The number of elements in table.
Definition: HashTableI.H:52
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:52
Foam::scalarList
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:64
Foam::symm
dimensionedSymmTensor symm(const dimensionedSymmTensor &dt)
Definition: dimensionedSymmTensor.C:84
Foam::globalPoints
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:102
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::labelMax
constexpr label labelMax
Definition: label.H:61
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::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::removePoints
Removes selected points from mesh and updates faces using these points.
Definition: removePoints.H:60
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::DynamicList< label >
Foam::polyTopoChange::removePoint
void removePoint(const label pointi, const label mergePointi)
Remove/merge point.
Definition: polyTopoChange.C:2678
Foam::polyTopoChange::removeCell
void removeCell(const label celli, const label mergeCelli)
Remove/merge cell.
Definition: polyTopoChange.C:2921
Foam::eigenValues
dimensionedVector eigenValues(const dimensionedSymmTensor &dt)
Definition: dimensionedTensor.C:149
globalMeshData.H
globalIndex.H
Foam::eigenVectors
dimensionedTensor eigenVectors(const dimensionedSymmTensor &dt)
Definition: dimensionedTensor.C:160
motionSmoother.H
polyTopoChange.H
Foam::polyTopoChange
Direct mesh changes based on v1.3 polyTopoChange syntax.
Definition: polyTopoChange.H:99
Foam::edge
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:63
Foam::edgeCollapser::markFaceZoneEdges
labelPair markFaceZoneEdges(const faceZone &fZone, const scalarField &faceFilterFactor, const labelList &pointPriority, bitSet &collapseEdge, Map< point > &collapsePointToLocation) const
Marks edges in the faceZone indirectPatchFaces for collapse.
Definition: edgeCollapser.C:1997
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
Foam::Map
A HashTable to objects of type <T> with a label key.
Definition: lumpedPointController.H:69
Foam::syncTools::swapBoundaryFaceList
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:439
Foam::orEqOp
Definition: ops.H:86
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:182
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::primitiveMesh::edges
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
Definition: primitiveMeshEdges.C:505
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::edgeCollapser::collapseType
collapseType
Definition: edgeCollapser.H:73
polyMesh.H
Foam::HashSet< label, Hash< label > >
Foam::incrIndent
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:327
syncTools.H
Foam::invert
labelList invert(const label len, const labelUList &map)
Create an inverse one-to-one mapping.
Definition: ListOps.C:36
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::syncTools::syncPointList
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
Definition: syncToolsTemplates.C:724
Foam::sumOp
Definition: ops.H:213
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::pointEdgeCollapse
Determines length of string of edges walked to point.
Definition: pointEdgeCollapse.H:61
Foam::minEqOp
Definition: ops.H:81
OFstream.H
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
removePoints.H
Foam::edgeCollapser::checkBadFaces
static labelHashSet checkBadFaces(const polyMesh &mesh, const dictionary &meshQualityDict)
Calls motionSmoother::checkMesh and returns a set of bad faces.
Definition: edgeCollapser.C:49
Foam::Field< vector >
Foam::faceZone
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
edgeCollapser.H
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
PointEdgeWave.H
Foam::syncTools::syncEdgeList
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh edges.
Definition: syncToolsTemplates.C:803
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
Foam::polyTopoChange::modifyFace
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip)
Modify vertices or cell of face.
Definition: polyTopoChange.C:2790
Foam::primitiveMesh::faceEdges
const labelListList & faceEdges() const
Definition: primitiveMeshEdges.C:528
Foam::ZoneMesh< pointZone, polyMesh >
Foam::symmTensor
SymmTensor< scalar > symmTensor
SymmTensor of scalars, i.e. SymmTensor<scalar>.
Definition: symmTensor.H:59
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
Foam::List::resize
void resize(const label newSize)
Adjust allocated size of list.
Definition: ListI.H:139
Foam::edgeCollapser::markSmallEdges
label markSmallEdges(const scalarField &minEdgeLen, const labelList &pointPriority, bitSet &collapseEdge, Map< point > &collapsePointToLocation) const
Mark (in collapseEdge) any edges to collapse.
Definition: edgeCollapser.C:1798
Foam::ZoneMesh::whichZone
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:315
newPointi
label newPointi
Definition: readKivaGrid.H:496
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::toPoint
PointFrompoint toPoint(const Foam::point &p)
Definition: pointConversion.H:82
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
zoneID
const labelIOList & zoneID
Definition: interpolatedFaces.H:22
Foam::edgeCollapser::setRefinement
bool setRefinement(const List< pointEdgeCollapse > &allPointInfo, polyTopoChange &meshMod) const
Play commands into polyTopoChange to create mesh.
Definition: edgeCollapser.C:1247
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::decrIndent
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:334
Foam::faceZone::whichFace
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:379
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:320
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::polyTopoChange::removeFace
void removeFace(const label facei, const label mergeFacei)
Remove/merge face.
Definition: polyTopoChange.C:2827
Foam::edgeCollapser::consistentCollapse
void consistentCollapse(const globalIndex &globalPoints, const labelList &pointPriority, const Map< point > &collapsePointToLocation, bitSet &collapseEdge, List< pointEdgeCollapse > &allPointInfo, const bool allowCellCollapse=false) const
Ensure that the collapse is parallel consistent and update.
Definition: edgeCollapser.C:1608
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
Foam::stringOps::match
bool match(const UList< wordRe > &patterns, const std::string &text)
Return true if text matches one of the regular expressions.
Definition: stringOps.H:75
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::Pair< label >
forAllConstIters
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
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::Vector< scalar >
Foam::polyTopoChange::modifyPoint
void modifyPoint(const label pointi, const point &pt, const label zoneID, const bool inCell)
Modify coordinate.
Definition: polyTopoChange.C:2617
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:115
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::labelMin
constexpr label labelMin
Definition: label.H:60
Foam::edgeCollapser::checkMeshQuality
static label checkMeshQuality(const polyMesh &mesh, const dictionary &meshQualityDict, bitSet &isErrorPoint)
Check mesh and mark points on faces in error.
Definition: edgeCollapser.C:85
Foam::boundaryMesh
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:62
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::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
Foam::det
dimensionedScalar det(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:62
Foam::sortedOrder
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
collapseEdge
label collapseEdge(triSurface &surf, const scalar minLen)
Keep collapsing all edges < minLen.
Foam::VectorSpace::size
static constexpr direction size() noexcept
The number of elements in the VectorSpace = Ncmpts.
Definition: VectorSpace.H:176
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:409
Foam::cbrt
dimensionedScalar cbrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:155
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:122
Foam::edgeCollapser::markSmallSliverFaces
labelPair markSmallSliverFaces(const scalarField &faceFilterFactor, const labelList &pointPriority, bitSet &collapseEdge, Map< point > &collapsePointToLocation) const
Find small faces and sliver faces in the mesh and mark the.
Definition: edgeCollapser.C:1936
Foam::faceZone::flipMap
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:271
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::edgeCollapser::markMergeEdges
label markMergeEdges(const scalar maxCos, const labelList &pointPriority, bitSet &collapseEdge, Map< point > &collapsePointToLocation) const
Mark (in collapseEdge) any edges to merge.
Definition: edgeCollapser.C:1849
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:303
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::removePoints::countPointUsage
label countPointUsage(const scalar minCos, boolList &pointCanBeDeleted) const
Mark in pointCanBeDeleted the points that can be deleted.
Definition: removePoints.C:148
pointLabels
labelList pointLabels(nPoints, -1)
Foam::average
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:328
Foam::pointEdgeCollapse::collapseIndex
label collapseIndex() const
Definition: pointEdgeCollapse.H:114