primitiveMeshCheck.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-2016 OpenFOAM Foundation
9  Copyright (C) 2019-2022 OpenCFD Ltd.
10  Copyright (C) 2026 Keysight Technologies
11 -------------------------------------------------------------------------------
12 License
13  This file is part of OpenFOAM.
14 
15  OpenFOAM is free software: you can redistribute it and/or modify it
16  under the terms of the GNU General Public License as published by
17  the Free Software Foundation, either version 3 of the License, or
18  (at your option) any later version.
19 
20  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
21  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  for more details.
24 
25  You should have received a copy of the GNU General Public License
26  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "primitiveMesh.H"
31 #include "pyramid.H"
32 #include "ListOps.H"
33 #include "unitConversion.H"
34 #include "SortableList.H"
35 #include "edgeHashes.H"
36 #include "primitiveMeshTools.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 Foam::scalar Foam::primitiveMesh::closedThreshold_ = 1.0e-6;
41 Foam::scalar Foam::primitiveMesh::aspectThreshold_ = 1000;
42 Foam::scalar Foam::primitiveMesh::nonOrthThreshold_ = 70; // deg
44 Foam::scalar Foam::primitiveMesh::planarCosAngle_ = 1.0e-6;
45 
46 
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
48 
50 (
51  const vectorField& areas,
52  const bool report,
53  const bitSet& internalOrCoupledFaces
54 ) const
55 {
56  DebugInFunction << "Checking if boundary is closed" << endl;
57 
58  // Loop through all boundary faces and sum up the face area vectors.
59  // For a closed boundary, this should be zero in all vector components
60 
61  solveVector sumClosed(Zero);
62  solveScalar sumMagClosedBoundary(0);
63 
64  for (label facei = nInternalFaces(); facei < areas.size(); facei++)
65  {
66  if (!internalOrCoupledFaces.size() || !internalOrCoupledFaces[facei])
67  {
68  sumClosed += areas[facei];
69  sumMagClosedBoundary += mag(areas[facei]);
70  }
71  }
72 
73  reduce(sumClosed, sumOp<solveVector>());
74  reduce(sumMagClosedBoundary, sumOp<solveScalar>());
75 
76  solveVector openness = sumClosed/(sumMagClosedBoundary + VSMALL);
77 
78  if (cmptMax(cmptMag(openness)) > closedThreshold_)
79  {
80  if (debug || report)
81  {
82  Info<< " ***Boundary openness " << openness
83  << " possible hole in boundary description."
84  << endl;
85  }
86 
87  return true;
88  }
89 
90  if (debug || report)
91  {
92  Info<< " Boundary openness " << openness << " OK."
93  << endl;
94  }
95 
96  return false;
97 }
98 
99 
101 (
102  const vectorField& faceAreas,
103  const scalarField& cellVolumes,
104  const bool report,
105  labelHashSet* setPtr,
106  labelHashSet* aspectSetPtr,
107  const Vector<label>& meshD
108 ) const
109 {
110  DebugInFunction << "Checking if cells are closed" << endl;
111 
112  // Check that all cells labels are valid
113  const cellList& c = cells();
114 
115  label nErrorClosed = 0;
116 
117  forAll(c, cI)
118  {
119  const cell& curCell = c[cI];
120 
121  if (min(curCell) < 0 || max(curCell) > nFaces())
122  {
123  if (setPtr)
124  {
125  setPtr->insert(cI);
126  }
127 
128  nErrorClosed++;
129  }
130  }
131 
132  if (nErrorClosed > 0)
133  {
134  if (debug || report)
135  {
136  Info<< " ***Cells with invalid face labels found, number of cells "
137  << nErrorClosed << endl;
138  }
139 
140  return true;
141  }
142 
143 
144  scalarField openness;
145  scalarField aspectRatio;
147  (
148  *this,
149  meshD,
150  faceAreas,
151  cellVolumes,
152  openness,
153  aspectRatio
154  );
155 
156  label nOpen = 0;
157  scalar maxOpennessCell = max(openness);
158  label nAspect = 0;
159  scalar maxAspectRatio = max(aspectRatio);
160 
161  // Check the sums
162  forAll(openness, celli)
163  {
164  if (openness[celli] > closedThreshold_)
165  {
166  if (setPtr)
167  {
168  setPtr->insert(celli);
169  }
170 
171  nOpen++;
172  }
173 
174  if (aspectRatio[celli] > aspectThreshold_)
175  {
176  if (aspectSetPtr)
177  {
178  aspectSetPtr->insert(celli);
179  }
180 
181  nAspect++;
182  }
183  }
184 
185  reduce(nOpen, sumOp<label>());
186  reduce(maxOpennessCell, maxOp<scalar>());
187 
188  reduce(nAspect, sumOp<label>());
189  reduce(maxAspectRatio, maxOp<scalar>());
190 
191 
192  if (nOpen > 0)
193  {
194  if (debug || report)
195  {
196  Info<< " ***Open cells found, max cell openness: "
197  << maxOpennessCell << ", number of open cells " << nOpen
198  << endl;
199  }
200 
201  return true;
202  }
203 
204  if (nAspect > 0)
205  {
206  if (debug || report)
207  {
208  Info<< " ***High aspect ratio cells found, Max aspect ratio: "
209  << maxAspectRatio
210  << ", number of cells " << nAspect
211  << endl;
212  }
213 
214  return true;
215  }
216 
217  if (debug || report)
218  {
219  Info<< " Max cell openness = " << maxOpennessCell << " OK." << nl
220  << " Max aspect ratio = " << maxAspectRatio << " OK."
221  << endl;
222  }
223 
224  return false;
225 }
226 
227 
229 (
230  const vectorField& faceAreas,
231  const bool report,
232  const bool detailedReport,
233  labelHashSet* setPtr
234 ) const
235 {
236  DebugInFunction << "Checking face area magnitudes" << endl;
237 
238  const scalarField magFaceAreas(mag(faceAreas));
239 
240  scalar minArea = GREAT;
241  scalar maxArea = -GREAT;
242 
243  forAll(magFaceAreas, facei)
244  {
245  if (magFaceAreas[facei] < VSMALL)
246  {
247  if (setPtr)
248  {
249  setPtr->insert(facei);
250  }
251  if (detailedReport)
252  {
253  if (isInternalFace(facei))
254  {
255  Pout<< "Zero or negative face area detected for "
256  << "internal face "<< facei << " between cells "
257  << faceOwner()[facei] << " and "
258  << faceNeighbour()[facei]
259  << ". Face area magnitude = " << magFaceAreas[facei]
260  << endl;
261  }
262  else
263  {
264  Pout<< "Zero or negative face area detected for "
265  << "boundary face " << facei << " next to cell "
266  << faceOwner()[facei] << ". Face area magnitude = "
267  << magFaceAreas[facei] << endl;
268  }
269  }
270  }
271 
272  minArea = min(minArea, magFaceAreas[facei]);
273  maxArea = max(maxArea, magFaceAreas[facei]);
274  }
275 
276  reduce(minArea, minOp<scalar>());
277  reduce(maxArea, maxOp<scalar>());
278 
279  if (minArea < VSMALL)
280  {
281  if (debug || report)
282  {
283  Info<< " ***Zero or negative face area detected. "
284  "Minimum area: " << minArea << endl;
285  }
286 
287  return true;
288  }
289 
290  if (debug || report)
291  {
292  Info<< " Minimum face area = " << minArea
293  << ". Maximum face area = " << maxArea
294  << ". Face area magnitudes OK." << endl;
295  }
296 
297  return false;
298 }
299 
300 
302 (
303  const scalarField& vols,
304  const bool report,
305  const bool detailedReport,
306  labelHashSet* setPtr
307 ) const
308 {
309  DebugInFunction << "Checking cell volumes" << endl;
310 
311  scalar minVolume = GREAT;
312  scalar maxVolume = -GREAT;
313 
314  label nNegVolCells = 0;
315 
316  forAll(vols, celli)
317  {
318  if (vols[celli] < VSMALL)
319  {
320  if (setPtr)
321  {
322  setPtr->insert(celli);
323  }
324  if (detailedReport)
325  {
326  Pout<< "Zero or negative cell volume detected for cell "
327  << celli << ". Volume = " << vols[celli] << endl;
328  }
329 
330  nNegVolCells++;
331  }
332 
333  minVolume = min(minVolume, vols[celli]);
334  maxVolume = max(maxVolume, vols[celli]);
335  }
336 
337  reduce(minVolume, minOp<scalar>());
338  reduce(maxVolume, maxOp<scalar>());
339  reduce(nNegVolCells, sumOp<label>());
340 
341  if (minVolume < VSMALL)
342  {
343  if (debug || report)
344  {
345  Info<< " ***Zero or negative cell volume detected. "
346  << "Minimum negative volume: " << minVolume
347  << ", Number of negative volume cells: " << nNegVolCells
348  << endl;
349  }
350 
351  return true;
352  }
353 
354  if (debug || report)
355  {
356  Info<< " Min volume = " << minVolume
357  << ". Max volume = " << maxVolume
358  << ". Total volume = " << gSum(vols)
359  << ". Cell volumes OK." << endl;
360  }
361 
362  return false;
363 }
364 
365 
367 (
368  const vectorField& fAreas,
369  const vectorField& cellCtrs,
370  const bool report,
371  labelHashSet* setPtr
372 ) const
373 {
374  DebugInFunction << "Checking mesh non-orthogonality" << endl;
375 
376  tmp<scalarField> tortho = primitiveMeshTools::faceOrthogonality
377  (
378  *this,
379  fAreas,
380  cellCtrs
381  );
382  const scalarField& ortho = tortho();
383 
384  // Severe nonorthogonality threshold
385  const scalar severeNonorthogonalityThreshold =
386  ::cos(degToRad(nonOrthThreshold_));
387 
388  scalar minDDotS = min(ortho);
389 
390  scalar sumDDotS = sum(ortho);
391 
392  label severeNonOrth = 0;
393 
394  label errorNonOrth = 0;
395 
396 
397  forAll(ortho, facei)
398  {
399  if (ortho[facei] < severeNonorthogonalityThreshold)
400  {
401  if (ortho[facei] > SMALL)
402  {
403  if (setPtr)
404  {
405  setPtr->insert(facei);
406  }
407 
408  severeNonOrth++;
409  }
410  else
411  {
412  if (setPtr)
413  {
414  setPtr->insert(facei);
415  }
416 
417  errorNonOrth++;
418  }
419  }
420  }
421 
422  reduce(minDDotS, minOp<scalar>());
423  reduce(sumDDotS, sumOp<scalar>());
424  reduce(severeNonOrth, sumOp<label>());
425  reduce(errorNonOrth, sumOp<label>());
426 
427  if (debug || report)
428  {
429  const label neiSize = returnReduce(ortho.size(), sumOp<label>());
430 
431  if (neiSize > 0)
432  {
433  if (debug || report)
434  {
435  Info<< " Mesh non-orthogonality Max: "
436  << radToDeg(::acos(minDDotS))
437  << " average: " << radToDeg(::acos(sumDDotS/neiSize))
438  << endl;
439  }
440  }
441 
442  if (severeNonOrth > 0)
443  {
444  Info<< " *Number of severely non-orthogonal faces: "
445  << severeNonOrth << "." << endl;
446  }
447  }
448 
449  if (errorNonOrth > 0)
450  {
451  if (debug || report)
452  {
453  Info<< " ***Number of non-orthogonality errors: "
454  << errorNonOrth << "." << endl;
455  }
456 
457  return true;
458  }
459 
460  if (debug || report)
461  {
462  Info<< " Non-orthogonality check OK." << endl;
463  }
464 
465  return false;
466 }
467 
468 
470 (
471  const pointField& points,
472  const vectorField& ctrs,
473  const bool report,
474  const bool detailedReport,
475  const scalar minPyrVol,
476  labelHashSet* setPtr
477 ) const
478 {
479  DebugInFunction << "Checking face orientation" << endl;
480 
481  const labelList& own = faceOwner();
482  const labelList& nei = faceNeighbour();
483  const faceList& f = faces();
484 
485 
486  scalarField ownPyrVol;
487  scalarField neiPyrVol;
489  (
490  *this,
491  points,
492  ctrs,
493  ownPyrVol,
494  neiPyrVol
495  );
496 
497 
498  label nErrorPyrs = 0;
499 
500  forAll(ownPyrVol, facei)
501  {
502  if (ownPyrVol[facei] < minPyrVol)
503  {
504  if (setPtr)
505  {
506  setPtr->insert(facei);
507  }
508  if (detailedReport)
509  {
510  Pout<< "Negative pyramid volume: " << ownPyrVol[facei]
511  << " for face " << facei << " " << f[facei]
512  << " and owner cell: " << own[facei] << endl
513  << "Owner cell vertex labels: "
514  << cells()[own[facei]].labels(faces())
515  << endl;
516  }
517 
518  nErrorPyrs++;
519  }
520 
521  if (isInternalFace(facei))
522  {
523  if (neiPyrVol[facei] < minPyrVol)
524  {
525  if (setPtr)
526  {
527  setPtr->insert(facei);
528  }
529  if (detailedReport)
530  {
531  Pout<< "Negative pyramid volume: " << neiPyrVol[facei]
532  << " for face " << facei << " " << f[facei]
533  << " and neighbour cell: " << nei[facei] << nl
534  << "Neighbour cell vertex labels: "
535  << cells()[nei[facei]].labels(faces())
536  << endl;
537  }
538  nErrorPyrs++;
539  }
540  }
541  }
542 
543  reduce(nErrorPyrs, sumOp<label>());
544 
545  if (nErrorPyrs > 0)
546  {
547  if (debug || report)
548  {
549  Info<< " ***Error in face pyramids: "
550  << nErrorPyrs << " faces are incorrectly oriented."
551  << endl;
552  }
553 
554  return true;
555  }
556 
557  if (debug || report)
558  {
559  Info<< " Face pyramids OK." << endl;
560  }
561 
562  return false;
563 }
564 
565 
567 (
568  const pointField& points,
569  const vectorField& fCtrs,
570  const vectorField& fAreas,
571  const vectorField& cellCtrs,
572  const bool report,
573  labelHashSet* setPtr
574 ) const
575 {
576  DebugInFunction << "Checking face skewness" << endl;
577 
578  // Warn if the skew correction vector is more than skewWarning times
579  // larger than the face area vector
580 
581  tmp<scalarField> tskewness = primitiveMeshTools::faceSkewness
582  (
583  *this,
584  points,
585  fCtrs,
586  fAreas,
587  cellCtrs
588  );
589  const scalarField& skewness = tskewness();
590 
591  scalar maxSkew = max(skewness);
592  label nWarnSkew = 0;
593 
594  forAll(skewness, facei)
595  {
596  // Check if the skewness vector is greater than the PN vector.
597  // This does not cause trouble but is a good indication of a poor mesh.
598  if (skewness[facei] > skewThreshold_)
599  {
600  if (setPtr)
601  {
602  setPtr->insert(facei);
603  }
604 
605  nWarnSkew++;
606  }
607  }
608 
609  reduce(maxSkew, maxOp<scalar>());
610  reduce(nWarnSkew, sumOp<label>());
611 
612  if (nWarnSkew > 0)
613  {
614  if (debug || report)
615  {
616  Info<< " ***Max skewness = " << maxSkew
617  << ", " << nWarnSkew << " highly skew faces detected"
618  " which may impair the quality of the results"
619  << endl;
620  }
621 
622  return true;
623  }
624 
625  if (debug || report)
626  {
627  Info<< " Max skewness = " << maxSkew << " OK." << endl;
628  }
629 
630  return false;
631 }
632 
633 
635 (
636  const pointField& points,
637  const vectorField& faceAreas,
638  const bool report,
639  const scalar maxDeg,
640  labelHashSet* setPtr
641 ) const
642 {
643  DebugInFunction << "Checking face angles" << endl;
644 
645  if (maxDeg < -SMALL || maxDeg > 180+SMALL)
646  {
648  << "maxDeg should be [0..180] but is now " << maxDeg
649  << exit(FatalError);
650  }
651 
652  const scalar maxSin = Foam::sin(degToRad(maxDeg));
653 
654 
655  tmp<scalarField> tfaceAngles = primitiveMeshTools::faceConcavity
656  (
657  maxSin,
658  *this,
659  points,
660  faceAreas
661  );
662  const scalarField& faceAngles = tfaceAngles();
663 
664  scalar maxEdgeSin = max(faceAngles);
665 
666  label nConcave = 0;
667 
668  forAll(faceAngles, facei)
669  {
670  if (faceAngles[facei] > SMALL)
671  {
672  nConcave++;
673 
674  if (setPtr)
675  {
676  setPtr->insert(facei);
677  }
678  }
679  }
680 
681  reduce(nConcave, sumOp<label>());
682  reduce(maxEdgeSin, maxOp<scalar>());
683 
684  if (nConcave > 0)
685  {
686  scalar maxConcaveDegr =
687  radToDeg(Foam::asin(Foam::min(1.0, maxEdgeSin)));
688 
689  if (debug || report)
690  {
691  Info<< " *There are " << nConcave
692  << " faces with concave angles between consecutive"
693  << " edges. Max concave angle = " << maxConcaveDegr
694  << " degrees." << endl;
695  }
696 
697  return true;
698  }
699 
700  if (debug || report)
701  {
702  Info<< " All angles in faces OK." << endl;
703  }
704 
705  return false;
706 }
707 
708 
710 (
711  const pointField& points,
712  const vectorField& faceCentres,
713  const vectorField& faceAreas,
714  const bool report,
715  const scalar warnFlatness,
716  labelHashSet* setPtr
717 ) const
718 {
719  DebugInFunction << "Checking face flatness" << endl;
720 
721  if (warnFlatness < 0 || warnFlatness > 1)
722  {
724  << "warnFlatness should be [0..1] but is " << warnFlatness
725  << exit(FatalError);
726  }
727 
728  const faceList& fcs = faces();
729 
730  tmp<scalarField> tfaceFlatness = primitiveMeshTools::faceFlatness
731  (
732  *this,
733  points,
734  faceCentres,
735  faceAreas
736  );
737  const scalarField& faceFlatness = tfaceFlatness();
738 
739  scalarField magAreas(mag(faceAreas));
740 
741  scalar minFlatness = GREAT;
742  scalar sumFlatness = 0;
743  label nSummed = 0;
744  label nWarped = 0;
745 
746  forAll(faceFlatness, facei)
747  {
748  if (fcs[facei].size() > 3 && magAreas[facei] > VSMALL)
749  {
750  sumFlatness += faceFlatness[facei];
751  nSummed++;
752 
753  minFlatness = min(minFlatness, faceFlatness[facei]);
754 
755  if (faceFlatness[facei] < warnFlatness)
756  {
757  nWarped++;
758 
759  if (setPtr)
760  {
761  setPtr->insert(facei);
762  }
763  }
764  }
765  }
766 
767 
768  reduce(nWarped, sumOp<label>());
769  reduce(minFlatness, minOp<scalar>());
770 
771  reduce(nSummed, sumOp<label>());
772  reduce(sumFlatness, sumOp<scalar>());
773 
774  if (debug || report)
775  {
776  if (nSummed > 0)
777  {
778  Info<< " Face flatness (1 = flat, 0 = butterfly) : min = "
779  << minFlatness << " average = " << sumFlatness / nSummed
780  << endl;
781  }
782  }
783 
784 
785  if (nWarped > 0)
786  {
787  if (debug || report)
788  {
789  Info<< " *There are " << nWarped
790  << " faces with ratio between projected and actual area < "
791  << warnFlatness << endl;
792 
793  Info<< " Minimum ratio (minimum flatness, maximum warpage) = "
794  << minFlatness << endl;
795  }
796 
797  return true;
798  }
799 
800  if (debug || report)
801  {
802  Info<< " All face flatness OK." << endl;
803  }
804 
805  return false;
806 }
807 
808 
810 (
811  const vectorField& fAreas,
812  const pointField& fCentres,
813  const bool report,
814  labelHashSet* setPtr
815 ) const
816 {
817  DebugInFunction << "Checking for concave cells" << endl;
818 
819  const cellList& c = cells();
820  const labelList& fOwner = faceOwner();
821 
822  label nConcaveCells = 0;
823 
824  forAll(c, celli)
825  {
826  const cell& cFaces = c[celli];
827 
828  bool concave = false;
829 
830  forAll(cFaces, i)
831  {
832  if (concave)
833  {
834  break;
835  }
836 
837  label fI = cFaces[i];
838 
839  const point& fC = fCentres[fI];
840 
841  vector fN = fAreas[fI];
842 
843  fN /= max(mag(fN), VSMALL);
844 
845  // Flip normal if required so that it is always pointing out of
846  // the cell
847  if (fOwner[fI] != celli)
848  {
849  fN *= -1;
850  }
851 
852  // Is the centre of any other face of the cell on the
853  // wrong side of the plane of this face?
854 
855  forAll(cFaces, j)
856  {
857  if (j != i)
858  {
859  label fJ = cFaces[j];
860 
861  const point& pt = fCentres[fJ];
862 
863  // If the cell is concave, the point will be on the
864  // positive normal side of the plane of f, defined by
865  // its centre and normal, and the angle between (pt -
866  // fC) and fN will be less than 90 degrees, so the dot
867  // product will be positive.
868 
869  vector pC = (pt - fC);
870 
871  pC /= max(mag(pC), VSMALL);
872 
873  if ((pC & fN) > -planarCosAngle_)
874  {
875  // Concave or planar face
876 
877  concave = true;
878 
879  if (setPtr)
880  {
881  setPtr->insert(celli);
882  }
883 
884  nConcaveCells++;
885 
886  break;
887  }
888  }
889  }
890  }
891  }
892 
893  reduce(nConcaveCells, sumOp<label>());
894 
895  if (nConcaveCells > 0)
896  {
897  if (debug || report)
898  {
899  Info<< " ***Concave cells (using face planes) found,"
900  << " number of cells: " << nConcaveCells << endl;
901  }
902 
903  return true;
904  }
905 
906  if (debug || report)
907  {
908  Info<< " Concave cell check OK." << endl;
909  }
910 
911  return false;
912 }
913 
914 
916 (
917  const bool report,
918  labelHashSet* setPtr
919 ) const
920 {
921  DebugInFunction << "Checking face ordering" << endl;
922 
923  // Check whether internal faces are ordered in the upper triangular order
924  const labelList& own = faceOwner();
925  const labelList& nei = faceNeighbour();
926 
927  const cellList& c = cells();
928 
929  label internal = nInternalFaces();
930 
931  // Has error occurred?
932  bool hasError = false;
933  // Multiple faces detected?
934  label nMultipleCells = 0;
935 
936  // Loop through faceCells once more and make sure that for internal cell
937  // the first label is smaller
938  for (label facei = 0; facei < internal; facei++)
939  {
940  if (own[facei] >= nei[facei])
941  {
942  hasError = true;
943 
944  if (setPtr)
945  {
946  setPtr->insert(facei);
947  }
948  }
949  }
950 
951  // Loop through all cells. For each cell, find the face that is internal
952  // and add it to the check list (upper triangular order).
953  // Once the list is completed, check it against the faceCell list
954 
955  forAll(c, celli)
956  {
957  const labelList& curFaces = c[celli];
958 
959  // Neighbouring cells
960  SortableList<label> nbr(curFaces.size());
961 
962  forAll(curFaces, i)
963  {
964  label facei = curFaces[i];
965 
966  if (facei >= nInternalFaces())
967  {
968  // Sort last
969  nbr[i] = labelMax;
970  }
971  else
972  {
973  label nbrCelli = nei[facei];
974 
975  if (nbrCelli == celli)
976  {
977  nbrCelli = own[facei];
978  }
979 
980  if (celli < nbrCelli)
981  {
982  // celli is master
983  nbr[i] = nbrCelli;
984  }
985  else
986  {
987  // nbrCell is master. Let it handle this face.
988  nbr[i] = labelMax;
989  }
990  }
991  }
992 
993  nbr.sort();
994 
995  // Now nbr holds the cellCells in incremental order. Check:
996  // - neighbouring cells appear only once. Since nbr is sorted this
997  // is simple check on consecutive elements
998  // - faces indexed in same order as nbr are incrementing as well.
999 
1000  label prevCell = nbr[0];
1001  label prevFace = curFaces[nbr.indices()[0]];
1002 
1003  bool hasMultipleFaces = false;
1004 
1005  for (label i = 1; i < nbr.size(); i++)
1006  {
1007  label thisCell = nbr[i];
1008  label thisFace = curFaces[nbr.indices()[i]];
1009 
1010  if (thisCell == labelMax)
1011  {
1012  break;
1013  }
1014 
1015  if (thisCell == prevCell)
1016  {
1017  hasMultipleFaces = true;
1018 
1019  if (setPtr)
1020  {
1021  setPtr->insert(prevFace);
1022  setPtr->insert(thisFace);
1023  }
1024  }
1025  else if (thisFace < prevFace)
1026  {
1027  hasError = true;
1028 
1029  if (setPtr)
1030  {
1031  setPtr->insert(thisFace);
1032  }
1033  }
1034 
1035  prevCell = thisCell;
1036  prevFace = thisFace;
1037  }
1038 
1039  if (hasMultipleFaces)
1040  {
1041  nMultipleCells++;
1042  }
1043  }
1044 
1045  Pstream::reduceOr(hasError);
1046  reduce(nMultipleCells, sumOp<label>());
1047 
1048  if ((debug || report) && nMultipleCells > 0)
1049  {
1050  Info<< " <<Found " << nMultipleCells
1051  << " neighbouring cells with multiple inbetween faces." << endl;
1052  }
1053 
1054  if (hasError)
1055  {
1056  if (debug || report)
1057  {
1058  Info<< " ***Faces not in upper triangular order." << endl;
1059  }
1060 
1061  return true;
1062  }
1063 
1064  if (debug || report)
1065  {
1066  Info<< " Upper triangular ordering OK." << endl;
1067  }
1068 
1069  return false;
1070 }
1071 
1072 
1074 (
1075  const bool report,
1076  labelHashSet* setPtr
1077 ) const
1078 {
1079  DebugInFunction << "Checking topological cell openness" << endl;
1080 
1081  label nOpenCells = 0;
1082 
1083  const faceList& f = faces();
1084  const cellList& c = cells();
1085 
1086  forAll(c, celli)
1087  {
1088  const labelList& curFaces = c[celli];
1089 
1090  const edgeList cellEdges = c[celli].edges(f);
1091 
1092  labelList edgeUsage(cellEdges.size(), Zero);
1093 
1094  forAll(curFaces, facei)
1095  {
1096  edgeList curFaceEdges = f[curFaces[facei]].edges();
1097 
1098  forAll(curFaceEdges, faceEdgeI)
1099  {
1100  const edge& curEdge = curFaceEdges[faceEdgeI];
1101 
1102  forAll(cellEdges, cellEdgeI)
1103  {
1104  if (cellEdges[cellEdgeI] == curEdge)
1105  {
1106  edgeUsage[cellEdgeI]++;
1107  break;
1108  }
1109  }
1110  }
1111  }
1112 
1113  edgeList singleEdges(cellEdges.size());
1114  label nSingleEdges = 0;
1115 
1116  forAll(edgeUsage, edgeI)
1117  {
1118  if (edgeUsage[edgeI] == 1)
1119  {
1120  singleEdges[nSingleEdges] = cellEdges[edgeI];
1121  nSingleEdges++;
1122  }
1123  else if (edgeUsage[edgeI] != 2)
1124  {
1125  if (setPtr)
1126  {
1127  setPtr->insert(celli);
1128  }
1129  }
1130  }
1131 
1132  if (nSingleEdges > 0)
1133  {
1134  if (setPtr)
1135  {
1136  setPtr->insert(celli);
1137  }
1138 
1139  nOpenCells++;
1140  }
1141  }
1142 
1143  reduce(nOpenCells, sumOp<label>());
1144 
1145  if (nOpenCells > 0)
1146  {
1147  if (debug || report)
1148  {
1149  Info<< " ***Open cells found, number of cells: " << nOpenCells
1150  << ". This problem may be fixable using the zipUpMesh utility."
1151  << endl;
1152  }
1153 
1154  return true;
1155  }
1156 
1157  if (debug || report)
1158  {
1159  Info<< " Topological cell zip-up check OK." << endl;
1160  }
1161 
1162  return false;
1163 }
1164 
1165 
1167 (
1168  const bool report,
1169  labelHashSet* setPtr
1170 ) const
1171 {
1172  DebugInFunction << "Checking face vertices" << endl;
1173 
1174  // Check that all vertex labels are valid
1175  const faceList& f = faces();
1176 
1177  label nErrorFaces = 0;
1178 
1179  forAll(f, fI)
1180  {
1181  const face& curFace = f[fI];
1182 
1183  if (min(curFace) < 0 || max(curFace) > nPoints())
1184  {
1185  if (setPtr)
1186  {
1187  setPtr->insert(fI);
1188  }
1189 
1190  nErrorFaces++;
1191  }
1192 
1193  // Uniqueness of vertices
1194  labelHashSet facePoints(2*curFace.size());
1195 
1196  forAll(curFace, fp)
1197  {
1198  bool inserted = facePoints.insert(curFace[fp]);
1199 
1200  if (!inserted)
1201  {
1202  if (setPtr)
1203  {
1204  setPtr->insert(fI);
1205  }
1206 
1207  nErrorFaces++;
1208  }
1209  }
1210  }
1211 
1212  reduce(nErrorFaces, sumOp<label>());
1213 
1214  if (nErrorFaces > 0)
1215  {
1216  if (debug || report)
1217  {
1218  Info<< " Faces with invalid vertex labels found, "
1219  << " number of faces: " << nErrorFaces << endl;
1220  }
1221 
1222  return true;
1223  }
1224 
1225  if (debug || report)
1226  {
1227  Info<< " Face vertices OK." << endl;
1228  }
1229 
1230  return false;
1231 }
1232 
1233 
1235 (
1236  const bool report,
1237  labelHashSet* setPtr
1238 ) const
1239 {
1240  DebugInFunction << "Checking points" << endl;
1241 
1242  label nFaceErrors = 0;
1243  label nCellErrors = 0;
1244 
1245  const labelListList& pf = pointFaces();
1246 
1247  forAll(pf, pointi)
1248  {
1249  if (pf[pointi].empty())
1250  {
1251  if (setPtr)
1252  {
1253  setPtr->insert(pointi);
1254  }
1255 
1256  nFaceErrors++;
1257  }
1258  }
1259 
1260 
1261  forAll(pf, pointi)
1262  {
1263  const labelList& pc = pointCells(pointi);
1264 
1265  if (pc.empty())
1266  {
1267  if (setPtr)
1268  {
1269  setPtr->insert(pointi);
1270  }
1271 
1272  nCellErrors++;
1273  }
1274  }
1275 
1276  reduce(nFaceErrors, sumOp<label>());
1277  reduce(nCellErrors, sumOp<label>());
1278 
1279  if (nFaceErrors > 0 || nCellErrors > 0)
1280  {
1281  if (debug || report)
1282  {
1283  Info<< " ***Unused points found in the mesh, "
1284  "number unused by faces: " << nFaceErrors
1285  << " number unused by cells: " << nCellErrors
1286  << endl;
1287  }
1288 
1289  return true;
1290  }
1291 
1292  if (debug || report)
1293  {
1294  Info<< " Point usage OK." << endl;
1295  }
1296 
1297  return false;
1298 }
1299 
1300 
1302 (
1303  const label facei,
1304  const Map<label>& nCommonPoints,
1305  label& nBaffleFaces,
1306  labelHashSet* setPtr
1307 ) const
1308 {
1309  bool error = false;
1310 
1311  forAllConstIters(nCommonPoints, iter)
1312  {
1313  label nbFacei = iter.key();
1314  label nCommon = iter();
1315 
1316  const face& curFace = faces()[facei];
1317  const face& nbFace = faces()[nbFacei];
1318 
1319  if (nCommon == nbFace.size() || nCommon == curFace.size())
1320  {
1321  if (nbFace.size() != curFace.size())
1322  {
1323  error = true;
1324  }
1325  else
1326  {
1327  nBaffleFaces++;
1328  }
1329 
1330  if (setPtr)
1331  {
1332  setPtr->insert(facei);
1333  setPtr->insert(nbFacei);
1334  }
1335  }
1336  }
1337 
1338  return error;
1339 }
1340 
1341 
1343 (
1344  const label facei,
1345  const Map<label>& nCommonPoints,
1346  labelHashSet* setPtr
1347 ) const
1348 {
1349  bool error = false;
1350 
1351  forAllConstIters(nCommonPoints, iter)
1352  {
1353  label nbFacei = iter.key();
1354  label nCommon = iter();
1355 
1356  const face& curFace = faces()[facei];
1357  const face& nbFace = faces()[nbFacei];
1358 
1359  if
1360  (
1361  nCommon >= 2
1362  && nCommon != nbFace.size()
1363  && nCommon != curFace.size()
1364  )
1365  {
1366  forAll(curFace, fp)
1367  {
1368  // Get the index in the neighbouring face shared with curFace
1369  label nb = nbFace.find(curFace[fp]);
1370 
1371  if (nb != -1)
1372  {
1373 
1374  // Check the whole face from nb onwards for shared vertices
1375  // with neighbouring face. Rule is that any shared vertices
1376  // should be consecutive on both faces i.e. if they are
1377  // vertices fp,fp+1,fp+2 on one face they should be
1378  // vertices nb, nb+1, nb+2 (or nb+2, nb+1, nb) on the
1379  // other face.
1380 
1381 
1382  // Vertices before and after on curFace
1383  label fpPlus1 = curFace.fcIndex(fp);
1384  label fpMin1 = curFace.rcIndex(fp);
1385 
1386  // Vertices before and after on nbFace
1387  label nbPlus1 = nbFace.fcIndex(nb);
1388  label nbMin1 = nbFace.rcIndex(nb);
1389 
1390  // Find order of walking by comparing next points on both
1391  // faces.
1392  label curInc = labelMax;
1393  label nbInc = labelMax;
1394 
1395  if (nbFace[nbPlus1] == curFace[fpPlus1])
1396  {
1397  curInc = 1;
1398  nbInc = 1;
1399  }
1400  else if (nbFace[nbPlus1] == curFace[fpMin1])
1401  {
1402  curInc = -1;
1403  nbInc = 1;
1404  }
1405  else if (nbFace[nbMin1] == curFace[fpMin1])
1406  {
1407  curInc = -1;
1408  nbInc = -1;
1409  }
1410  else
1411  {
1412  curInc = 1;
1413  nbInc = -1;
1414  }
1415 
1416 
1417  // Pass1: loop until start of common vertices found.
1418  label curNb = nb;
1419  label curFp = fp;
1420 
1421  do
1422  {
1423  curFp += curInc;
1424 
1425  if (curFp >= curFace.size())
1426  {
1427  curFp = 0;
1428  }
1429  else if (curFp < 0)
1430  {
1431  curFp = curFace.size()-1;
1432  }
1433 
1434  curNb += nbInc;
1435 
1436  if (curNb >= nbFace.size())
1437  {
1438  curNb = 0;
1439  }
1440  else if (curNb < 0)
1441  {
1442  curNb = nbFace.size()-1;
1443  }
1444  } while (curFace[curFp] == nbFace[curNb]);
1445 
1446 
1447  // Pass2: check equality walking from curFp, curNb
1448  // in opposite order.
1449 
1450  curInc = -curInc;
1451  nbInc = -nbInc;
1452 
1453  for (label commonI = 0; commonI < nCommon; commonI++)
1454  {
1455  curFp += curInc;
1456 
1457  if (curFp >= curFace.size())
1458  {
1459  curFp = 0;
1460  }
1461  else if (curFp < 0)
1462  {
1463  curFp = curFace.size()-1;
1464  }
1465 
1466  curNb += nbInc;
1467 
1468  if (curNb >= nbFace.size())
1469  {
1470  curNb = 0;
1471  }
1472  else if (curNb < 0)
1473  {
1474  curNb = nbFace.size()-1;
1475  }
1476 
1477  if (curFace[curFp] != nbFace[curNb])
1478  {
1479  if (setPtr)
1480  {
1481  setPtr->insert(facei);
1482  setPtr->insert(nbFacei);
1483  }
1484 
1485  error = true;
1486 
1487  break;
1488  }
1489  }
1490 
1491 
1492  // Done the curFace - nbFace combination.
1493  break;
1494  }
1495  }
1496  }
1497  }
1498 
1499  return error;
1500 }
1501 
1502 
1504 (
1505  const bool report,
1506  labelHashSet* setPtr
1507 ) const
1508 {
1509  DebugInFunction << "Checking face-face connectivity" << endl;
1510 
1511  const labelListList& pf = pointFaces();
1512 
1513  label nBaffleFaces = 0;
1514  label nErrorDuplicate = 0;
1515  label nErrorOrder = 0;
1516  Map<label> nCommonPoints;
1517 
1518  for (label facei = 0; facei < nFaces(); facei++)
1519  {
1520  const face& curFace = faces()[facei];
1521 
1522  // Calculate number of common points between current facei and
1523  // neighbouring face. Store on map.
1524  nCommonPoints.clear();
1525 
1526  forAll(curFace, fp)
1527  {
1528  label pointi = curFace[fp];
1529 
1530  const labelList& nbs = pf[pointi];
1531 
1532  forAll(nbs, nbI)
1533  {
1534  label nbFacei = nbs[nbI];
1535 
1536  if (facei < nbFacei)
1537  {
1538  // Only check once for each combination of two faces.
1539  ++(nCommonPoints(nbFacei, 0));
1540  }
1541  }
1542  }
1543 
1544  // Perform various checks on common points
1545 
1546  // Check all vertices shared (duplicate point)
1547  if (checkDuplicateFaces(facei, nCommonPoints, nBaffleFaces, setPtr))
1548  {
1549  nErrorDuplicate++;
1550  }
1551 
1552  // Check common vertices are consecutive on both faces
1553  if (checkCommonOrder(facei, nCommonPoints, setPtr))
1554  {
1555  nErrorOrder++;
1556  }
1557  }
1558 
1559  reduce(nBaffleFaces, sumOp<label>());
1560  reduce(nErrorDuplicate, sumOp<label>());
1561  reduce(nErrorOrder, sumOp<label>());
1562 
1563  if (nBaffleFaces)
1564  {
1565  Info<< " Number of identical duplicate faces (baffle faces): "
1566  << nBaffleFaces << endl;
1567  }
1568 
1569  if (nErrorDuplicate > 0 || nErrorOrder > 0)
1570  {
1571  // These are actually warnings, not errors.
1572  if (nErrorDuplicate > 0)
1573  {
1574  Info<< " <<Number of duplicate (not baffle) faces found: "
1575  << nErrorDuplicate
1576  << ". This might indicate a problem." << endl;
1577  }
1578 
1579  if (nErrorOrder > 0)
1580  {
1581  Info<< " <<Number of faces with non-consecutive shared points: "
1582  << nErrorOrder << ". This might indicate a problem." << endl;
1583  }
1584 
1585  return false; //return true;
1586  }
1587 
1588  if (debug || report)
1589  {
1590  Info<< " Face-face connectivity OK." << endl;
1591  }
1593  return false;
1594 }
1595 
1596 
1597 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1598 
1599 bool Foam::primitiveMesh::checkClosedBoundary(const bool report) const
1600 {
1601  return checkClosedBoundary(faceAreas(), report, bitSet());
1602 }
1603 
1604 
1606 (
1607  const bool report,
1608  labelHashSet* setPtr,
1609  labelHashSet* aspectSetPtr,
1610  const Vector<label>& solutionD
1611 ) const
1612 {
1613  return checkClosedCells
1614  (
1615  faceAreas(),
1616  cellVolumes(),
1617  report,
1618  setPtr,
1619  aspectSetPtr,
1620  solutionD
1621  );
1622 }
1623 
1624 
1626 (
1627  const bool report,
1628  labelHashSet* setPtr
1629 ) const
1630 {
1631  return checkFaceAreas
1632  (
1633  faceAreas(),
1634  report,
1635  false, // detailedReport,
1636  setPtr
1637  );
1638 }
1639 
1640 
1642 (
1643  const bool report,
1644  labelHashSet* setPtr
1645 ) const
1646 {
1647  return checkCellVolumes
1648  (
1649  cellVolumes(),
1650  report,
1651  false, // detailedReport,
1652  setPtr
1653  );
1654 }
1655 
1656 
1658 (
1659  const bool report,
1660  labelHashSet* setPtr
1661 ) const
1662 {
1663  return checkFaceOrthogonality
1664  (
1665  faceAreas(),
1666  cellCentres(),
1667  report,
1668  setPtr
1669  );
1670 }
1671 
1672 
1674 (
1675  const bool report,
1676  const scalar minPyrVol,
1677  labelHashSet* setPtr
1678 ) const
1679 {
1680  return checkFacePyramids
1681  (
1682  points(),
1683  cellCentres(),
1684  report,
1685  false, // detailedReport,
1686  minPyrVol,
1687  setPtr
1688  );
1689 }
1690 
1691 
1693 (
1694  const bool report,
1695  labelHashSet* setPtr
1696 ) const
1697 {
1698  return checkFaceSkewness
1699  (
1700  points(),
1701  faceCentres(),
1702  faceAreas(),
1703  cellCentres(),
1704  report,
1705  setPtr
1706  );
1707 }
1708 
1709 
1711 (
1712  const bool report,
1713  const scalar maxDeg,
1714  labelHashSet* setPtr
1715 ) const
1716 {
1717  return checkFaceAngles
1718  (
1719  points(),
1720  faceAreas(),
1721  report,
1722  maxDeg,
1723  setPtr
1724  );
1725 }
1726 
1727 
1729 (
1730  const bool report,
1731  const scalar warnFlatness,
1732  labelHashSet* setPtr
1733 ) const
1734 {
1735  return checkFaceFlatness
1736  (
1737  points(),
1738  faceCentres(),
1739  faceAreas(),
1740  report,
1741  warnFlatness,
1742  setPtr
1743  );
1744 }
1745 
1746 
1748 (
1749  const bool report,
1750  labelHashSet* setPtr
1751 ) const
1752 {
1753  return checkConcaveCells
1754  (
1755  faceAreas(),
1756  faceCentres(),
1757  report,
1758  setPtr
1759  );
1760 }
1761 
1762 
1763 bool Foam::primitiveMesh::checkTopology(const bool report) const
1764 {
1765  label nFailedChecks = 0;
1766 
1767  if (checkPoints(report)) ++nFailedChecks;
1768  if (checkUpperTriangular(report)) ++nFailedChecks;
1769  if (checkCellsZipUp(report)) ++nFailedChecks;
1770  if (checkFaceVertices(report)) ++nFailedChecks;
1771  if (checkFaceFaces(report)) ++nFailedChecks;
1772 
1773  if (nFailedChecks)
1774  {
1775  if (debug || report)
1776  {
1777  Info<< " Failed " << nFailedChecks
1778  << " mesh topology checks." << endl;
1779  }
1780 
1781  return true;
1782  }
1783 
1784  if (debug || report)
1785  {
1786  Info<< " Mesh topology OK." << endl;
1787  }
1788 
1789  return false;
1790 }
1791 
1792 
1793 bool Foam::primitiveMesh::checkGeometry(const bool report) const
1794 {
1795  label nFailedChecks = 0;
1796 
1797  if (checkClosedBoundary(report)) ++nFailedChecks;
1798  if (checkClosedCells(report)) ++nFailedChecks;
1799  if (checkFaceAreas(report)) ++nFailedChecks;
1800  if (checkCellVolumes(report)) ++nFailedChecks;
1801  if (checkFaceOrthogonality(report)) ++nFailedChecks;
1802  if (checkFacePyramids(report)) ++nFailedChecks;
1803  if (checkFaceSkewness(report)) ++nFailedChecks;
1804 
1805  if (nFailedChecks)
1806  {
1807  if (debug || report)
1808  {
1809  Info<< " Failed " << nFailedChecks
1810  << " mesh geometry checks." << endl;
1811  }
1812 
1813  return true;
1814  }
1815 
1816  if (debug || report)
1817  {
1818  Info<< " Mesh geometry OK." << endl;
1819  }
1820 
1821  return false;
1822 }
1823 
1824 
1825 bool Foam::primitiveMesh::checkBoundary(const bool report) const
1826 {
1827  // No boundary patch knowledge at primitiveMesh level - no-op
1828  return false;
1829 }
1830 
1831 
1832 bool Foam::primitiveMesh::checkMesh(const bool report) const
1833 {
1834  DebugInFunction << "Checking primitiveMesh" << endl;
1835 
1836  label nFailedChecks =
1837  checkTopology(report)
1838  + checkGeometry(report)
1839  + checkBoundary(report);
1840 
1841  if (nFailedChecks)
1842  {
1843  if (debug || report)
1844  {
1845  Info<< " Failed " << nFailedChecks
1846  << " mesh checks." << endl;
1847  }
1848 
1849  return true;
1850  }
1851 
1852  if (debug || report)
1853  {
1854  Info<< "Mesh OK." << endl;
1855  }
1856 
1857  return false;
1858 }
1859 
1860 
1861 Foam::scalar Foam::primitiveMesh::setClosedThreshold(const scalar val)
1862 {
1863  scalar prev = closedThreshold_;
1864  closedThreshold_ = val;
1865 
1866  return prev;
1867 }
1868 
1869 
1870 Foam::scalar Foam::primitiveMesh::setAspectThreshold(const scalar val)
1871 {
1872  scalar prev = aspectThreshold_;
1873  aspectThreshold_ = val;
1874 
1875  return prev;
1876 }
1877 
1878 
1879 Foam::scalar Foam::primitiveMesh::setNonOrthThreshold(const scalar val)
1880 {
1881  scalar prev = nonOrthThreshold_;
1882  nonOrthThreshold_ = val;
1883 
1884  return prev;
1885 }
1886 
1887 
1888 Foam::scalar Foam::primitiveMesh::setSkewThreshold(const scalar val)
1889 {
1890  scalar prev = skewThreshold_;
1891  skewThreshold_ = val;
1892 
1893  return prev;
1894 }
1895 
1896 
1897 // ************************************************************************* //
bool checkFaceAreas(const vectorField &faceAreas, const bool report, const bool detailedReport, labelHashSet *setPtr) const
Check for negative face areas.
static scalar aspectThreshold_
Aspect ratio warning threshold.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
dimensionedScalar acos(const dimensionedScalar &ds)
void cmptMax(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
bool checkFaceAngles(const pointField &points, const vectorField &faceAreas, const bool report, const scalar maxDeg, labelHashSet *setPtr) const
Check face angles.
List< cell > cellList
List of cell.
Definition: cellListFwd.H:39
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
Unit conversion functions.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label checkTopology(const polyMesh &mesh, const bool allTopology, const bool allGeometry, autoPtr< surfaceWriter > &surfWriter, autoPtr< coordSetWriter > &setWriter, const bool writeBadEdges=false)
static scalar setClosedThreshold(const scalar)
Set the closedness ratio warning threshold.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
static tmp< scalarField > faceConcavity(const scalar maxSin, const primitiveMesh &mesh, const pointField &p, const vectorField &faceAreas)
Generate face concavity field. Returns per face the (sin of the) most concave angle between two conse...
static void reduceOr(bool &value, const int communicator=UPstream::worldComm)
Logical (or) reduction (MPI_AllReduce)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
dimensionedScalar asin(const dimensionedScalar &ds)
static scalar setAspectThreshold(const scalar)
Set the aspect ratio warning threshold.
bool checkClosedBoundary(const vectorField &areas, const bool report, const bitSet &internalOrCoupledFaces) const
Check boundary for closedness.
Various functions to operate on Lists.
void reduce(T &value, [[maybe_unused]] BinaryOp bop, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce)
static scalar setSkewThreshold(const scalar)
Set the skewness warning threshold as percentage.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:74
bool checkFaceSkewness(const pointField &points, const vectorField &fCtrs, const vectorField &fAreas, const vectorField &cellCtrs, const bool report, labelHashSet *setPtr) const
Check face skewness.
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
bool checkClosedCells(const vectorField &faceAreas, const scalarField &cellVolumes, const bool report, labelHashSet *setPtr, labelHashSet *aspectSetPtr, const Vector< label > &meshD) const
Check cells for closedness.
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
static tmp< scalarField > faceSkewness(const primitiveMesh &mesh, const pointField &points, const vectorField &fCtrs, const vectorField &fAreas, const vectorField &cellCtrs)
Generate skewness field.
bool checkFacePyramids(const pointField &points, const vectorField &ctrs, const bool report, const bool detailedReport, const scalar minPyrVol, labelHashSet *setPtr) const
Check face pyramid volume.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
Type gSum(const FieldField< Field, Type > &f)
dimensionedScalar cos(const dimensionedScalar &ds)
const cellShapeList & cells
const pointField & points
bool checkFaceOrthogonality(const vectorField &fAreas, const vectorField &cellCtrs, const bool report, labelHashSet *setPtr) const
Check for non-orthogonality.
static scalar closedThreshold_
Static data to control mesh checking.
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
void clear()
Remove all entries from table.
Definition: HashTable.C:742
virtual bool checkMesh(const bool report=false) const
Check mesh for correctness. Returns false for no error.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
label nInternalFaces() const noexcept
Number of internal faces.
Vector< scalar > vector
Definition: vector.H:57
static scalar setNonOrthThreshold(const scalar)
Set the non-orthogonality warning threshold in degrees.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
bool checkCellVolumes(const scalarField &vols, const bool report, const bool detailedReport, labelHashSet *setPtr) const
Check for negative cell volumes.
Templated 3D Vector derived from VectorSpace adding construction from 3 components, element access using x(), y() and z() member functions and the inner-product (dot-product) and cross-product operators.
Definition: Vector.H:58
static scalar planarCosAngle_
Threshold where faces are considered coplanar.
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
dimensionedScalar sin(const dimensionedScalar &ds)
static void facePyramidVolume(const primitiveMesh &mesh, const pointField &points, const vectorField &cellCtrs, scalarField &ownPyrVol, scalarField &neiPyrVol)
Generate face pyramid volume fields.
int debug
Static debugging option.
const wordList edge
Standard (finite-area) edge field types (scalar, vector, tensor, etc)
labelList f(nPoints)
virtual bool checkFaceVertices(const bool report=false, labelHashSet *setPtr=nullptr) const
Check uniqueness of face vertices.
virtual bool checkTopology(const bool report=false) const
Check mesh topology for correctness.
vector point
Point is a vector.
Definition: point.H:37
virtual bool checkBoundary(const bool report=false) const
Check boundary patches (e.g. empty and wedge) for correct.
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:58
bool checkConcaveCells(const vectorField &fAreas, const pointField &fCentres, const bool report, labelHashSet *setPtr) const
Check for concave cells by the planes of faces.
constexpr scalar radToDeg(const scalar rad) noexcept
Conversion from radians to degrees.
bool checkCommonOrder(const label, const Map< label > &, labelHashSet *) const
Check that shared points are in consecutive order.
const dimensionedScalar c
Speed of light in a vacuum.
bool checkDuplicateFaces(const label, const Map< label > &, label &nBaffleFaces, labelHashSet *) const
Check if all points on face are shared with another face.
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
virtual bool checkCellsZipUp(const bool report=false, labelHashSet *setPtr=nullptr) const
Check cell zip-up.
virtual bool checkUpperTriangular(const bool report=false, labelHashSet *setPtr=nullptr) const
Check face ordering.
virtual bool checkPoints(const bool report=false, labelHashSet *setPtr=nullptr) const
Check for unused points.
virtual bool checkGeometry(const bool report=false) const
Check mesh geometry (& implicitly topology) for correctness.
Field< vector > vectorField
Specialisation of Field<T> for vector.
bool checkFaceFlatness(const pointField &points, const vectorField &faceCentres, const vectorField &faceAreas, const bool report, const scalar warnFlatness, labelHashSet *setPtr) const
Check face warpage.
virtual bool checkFaceFaces(const bool report=false, labelHashSet *setPtr=nullptr) const
Check face-face connectivity.
static tmp< scalarField > faceOrthogonality(const primitiveMesh &mesh, const vectorField &fAreas, const vectorField &cellCtrs)
Generate non-orthogonality field (internal faces only)
static scalar skewThreshold_
Skewness warning threshold.
List< label > labelList
A List of labels.
Definition: List.H:61
static scalar nonOrthThreshold_
Non-orthogonality warning threshold in deg.
static void cellClosedness(const primitiveMesh &mesh, const Vector< label > &meshD, const vectorField &areas, const scalarField &vols, scalarField &openness, scalarField &aratio)
Generate cell openness and cell aspect ratio field.
static tmp< scalarField > faceFlatness(const primitiveMesh &mesh, const pointField &p, const vectorField &fCtrs, const vectorField &faceAreas)
Generate face flatness field. Compares the individual triangles&#39; normals against the face average nor...
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
label size() const noexcept
Number of entries.
Definition: PackedList.H:392
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
label checkGeometry(const polyMesh &mesh, const bool allGeometry, autoPtr< surfaceWriter > &surfWriter, autoPtr< coordSetWriter > &setWriter)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127