primitiveMeshCheck.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "primitiveMeshCheck.H"
27 #include "pyramidPointFaceRef.H"
28 #include "PackedBoolList.H"
29 #include "unitConversion.H"
30 #include "SortableList.H"
31 
32 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
33 
35 (
36  const primitiveMesh& mesh,
37  const pointField& p,
38  const vectorField& fCtrs,
39  const vectorField& fAreas,
40 
41  const label facei,
42  const point& ownCc,
43  const point& neiCc
44 )
45 {
46  const vector Cpf = fCtrs[facei] - ownCc;
47  const vector d = neiCc - ownCc;
48 
49  // Skewness vector
50  const vector sv =
51  Cpf
52  - ((fAreas[facei] & Cpf)/((fAreas[facei] & d) + rootVSmall))*d;
53  const vector svHat = sv/(mag(sv) + rootVSmall);
54 
55  // Normalisation distance calculated as the approximate distance
56  // from the face centre to the edge of the face in the direction
57  // of the skewness
58  scalar fd = 0.2*mag(d) + rootVSmall;
59  const face& f = mesh.faces()[facei];
60  forAll(f, pi)
61  {
62  fd = max(fd, mag(svHat & (p[f[pi]] - fCtrs[facei])));
63  }
64 
65  // Normalised skewness
66  return mag(sv)/fd;
67 }
68 
69 
71 (
72  const primitiveMesh& mesh,
73  const pointField& p,
74  const vectorField& fCtrs,
75  const vectorField& fAreas,
76 
77  const label facei,
78  const point& ownCc
79 )
80 {
81  const vector Cpf = fCtrs[facei] - ownCc;
82 
83  vector normal = fAreas[facei];
84  normal /= mag(normal) + rootVSmall;
85  const vector d = normal*(normal & Cpf);
86 
87 
88  // Skewness vector
89  const vector sv =
90  Cpf
91  - ((fAreas[facei] & Cpf)/((fAreas[facei] & d) + rootVSmall))*d;
92  const vector svHat = sv/(mag(sv) + rootVSmall);
93 
94  // Normalisation distance calculated as the approximate distance
95  // from the face centre to the edge of the face in the direction
96  // of the skewness
97  scalar fd = 0.4*mag(d) + rootVSmall;
98  const face& f = mesh.faces()[facei];
99  forAll(f, pi)
100  {
101  fd = max(fd, mag(svHat & (p[f[pi]] - fCtrs[facei])));
102  }
103 
104  // Normalised skewness
105  return mag(sv)/fd;
106 }
107 
108 
110 (
111  const point& ownCc,
112  const point& neiCc,
113  const vector& s
114 )
115 {
116  const vector d = neiCc - ownCc;
117  return (d & s)/(mag(d)*mag(s) + rootVSmall);
118 }
119 
120 
121 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
122 
124 (
125  const primitiveMesh& mesh,
126  const vectorField& areas,
127  const vectorField& cc
128 )
129 {
130  const labelList& own = mesh.faceOwner();
131  const labelList& nei = mesh.faceNeighbour();
132 
133  tmp<scalarField> tortho(new scalarField(mesh.nInternalFaces()));
134  scalarField& ortho = tortho.ref();
135 
136  // Internal faces
137  forAll(nei, facei)
138  {
139  ortho[facei] = faceOrthogonality
140  (
141  cc[own[facei]],
142  cc[nei[facei]],
143  areas[facei]
144  );
145  }
146 
147  return tortho;
148 }
149 
150 
152 (
153  const primitiveMesh& mesh,
154  const pointField& p,
155  const vectorField& fCtrs,
156  const vectorField& fAreas,
157  const vectorField& cellCtrs
158 )
159 {
160  const labelList& own = mesh.faceOwner();
161  const labelList& nei = mesh.faceNeighbour();
162 
163  tmp<scalarField> tskew(new scalarField(mesh.nFaces()));
164  scalarField& skew = tskew.ref();
165 
166  forAll(nei, facei)
167  {
168  skew[facei] = faceSkewness
169  (
170  mesh,
171  p,
172  fCtrs,
173  fAreas,
174 
175  facei,
176  cellCtrs[own[facei]],
177  cellCtrs[nei[facei]]
178  );
179  }
180 
181 
182  // Boundary faces: consider them to have only skewness error.
183  // (i.e. treat as if mirror cell on other side)
184 
185  for (label facei = mesh.nInternalFaces(); facei < mesh.nFaces(); facei++)
186  {
187  skew[facei] = boundaryFaceSkewness
188  (
189  mesh,
190  p,
191  fCtrs,
192  fAreas,
193  facei,
194  cellCtrs[own[facei]]
195  );
196  }
197 
198  return tskew;
199 }
200 
201 
203 (
204  const primitiveMesh& mesh,
205  const pointField& points,
206  const vectorField& ctrs,
207 
208  scalarField& ownPyrVol,
209  scalarField& neiPyrVol
210 )
211 {
212  const labelList& own = mesh.faceOwner();
213  const labelList& nei = mesh.faceNeighbour();
214  const faceList& f = mesh.faces();
215 
216  ownPyrVol.setSize(mesh.nFaces());
217  neiPyrVol.setSize(mesh.nInternalFaces());
218 
219  forAll(f, facei)
220  {
221  // Create the owner pyramid
222  ownPyrVol[facei] = -pyramidPointFaceRef
223  (
224  f[facei],
225  ctrs[own[facei]]
226  ).mag(points);
227 
228  if (mesh.isInternalFace(facei))
229  {
230  // Create the neighbour pyramid - it will have positive volume
231  neiPyrVol[facei] = pyramidPointFaceRef
232  (
233  f[facei],
234  ctrs[nei[facei]]
235  ).mag(points);
236  }
237  }
238 }
239 
240 
242 (
243  const primitiveMesh& mesh,
244  const Vector<label>& meshD,
245  const vectorField& areas,
246  const scalarField& vols,
247 
248  scalarField& openness,
249  scalarField& aratio
250 )
251 {
252  const labelList& own = mesh.faceOwner();
253  const labelList& nei = mesh.faceNeighbour();
254 
255  // Loop through cell faces and sum up the face area vectors for each cell.
256  // This should be zero in all vector components
257 
258  vectorField sumClosed(mesh.nCells(), Zero);
259  vectorField sumMagClosed(mesh.nCells(), Zero);
260 
261  forAll(own, facei)
262  {
263  // Add to owner
264  sumClosed[own[facei]] += areas[facei];
265  sumMagClosed[own[facei]] += cmptMag(areas[facei]);
266  }
267 
268  forAll(nei, facei)
269  {
270  // Subtract from neighbour
271  sumClosed[nei[facei]] -= areas[facei];
272  sumMagClosed[nei[facei]] += cmptMag(areas[facei]);
273  }
274 
275 
276  label nDims = 0;
277  for (direction dir = 0; dir < vector::nComponents; dir++)
278  {
279  if (meshD[dir] == 1)
280  {
281  nDims++;
282  }
283  }
284 
285 
286  // Check the sums
287  openness.setSize(mesh.nCells());
288  aratio.setSize(mesh.nCells());
289 
290  forAll(sumClosed, celli)
291  {
292  scalar maxOpenness = 0;
293 
294  for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
295  {
296  maxOpenness = max
297  (
298  maxOpenness,
299  mag(sumClosed[celli][cmpt])
300  /(sumMagClosed[celli][cmpt] + rootVSmall)
301  );
302  }
303  openness[celli] = maxOpenness;
304 
305  // Calculate the aspect ration as the maximum of Cartesian component
306  // aspect ratio to the total area hydraulic area aspect ratio
307  scalar minCmpt = vGreat;
308  scalar maxCmpt = -vGreat;
309  for (direction dir = 0; dir < vector::nComponents; dir++)
310  {
311  if (meshD[dir] == 1)
312  {
313  minCmpt = min(minCmpt, sumMagClosed[celli][dir]);
314  maxCmpt = max(maxCmpt, sumMagClosed[celli][dir]);
315  }
316  }
317 
318  scalar aspectRatio = maxCmpt/(minCmpt + rootVSmall);
319  if (nDims == 3)
320  {
321  scalar v = max(rootVSmall, vols[celli]);
322 
323  aspectRatio = max
324  (
325  aspectRatio,
326  1.0/6.0*cmptSum(sumMagClosed[celli])/pow(v, 2.0/3.0)
327  );
328  }
329 
330  aratio[celli] = aspectRatio;
331  }
332 }
333 
334 
336 (
337  const scalar maxSin,
338  const primitiveMesh& mesh,
339  const pointField& p,
340  const vectorField& faceAreas
341 )
342 {
343  const faceList& fcs = mesh.faces();
344 
345  vectorField faceNormals(faceAreas);
346  faceNormals /= mag(faceNormals) + rootVSmall;
347 
348  tmp<scalarField> tfaceAngles(new scalarField(mesh.nFaces()));
349  scalarField& faceAngles = tfaceAngles.ref();
350 
351 
352  forAll(fcs, facei)
353  {
354  const face& f = fcs[facei];
355 
356  // Get edge from f[0] to f[size-1];
357  vector ePrev(p[f.first()] - p[f.last()]);
358  scalar magEPrev = mag(ePrev);
359  ePrev /= magEPrev + rootVSmall;
360 
361  scalar maxEdgeSin = 0.0;
362 
363  forAll(f, fp0)
364  {
365  // Get vertex after fp
366  const label fp1 = f.fcIndex(fp0);
367 
368  // Normalised vector between two consecutive points
369  vector e10(p[f[fp1]] - p[f[fp0]]);
370  const scalar magE10 = mag(e10);
371  e10 /= magE10 + rootVSmall;
372 
373  if (magEPrev > small && magE10 > small)
374  {
375  vector edgeNormal = ePrev ^ e10;
376  const scalar magEdgeNormal = mag(edgeNormal);
377 
378  if (magEdgeNormal < maxSin)
379  {
380  // Edges (almost) aligned -> face is ok.
381  }
382  else
383  {
384  // Check normal
385  edgeNormal /= magEdgeNormal;
386 
387  if ((edgeNormal & faceNormals[facei]) < small)
388  {
389  maxEdgeSin = max(maxEdgeSin, magEdgeNormal);
390  }
391  }
392  }
393 
394  ePrev = e10;
395  magEPrev = magE10;
396  }
397 
398  faceAngles[facei] = maxEdgeSin;
399  }
400 
401  return tfaceAngles;
402 }
403 
404 
406 (
407  const primitiveMesh& mesh,
408  const pointField& p,
409  const vectorField& fCtrs,
410  const vectorField& faceAreas
411 )
412 {
413  const faceList& fcs = mesh.faces();
414 
415  // Areas are calculated as the sum of areas. (see
416  // primitiveMeshFaceCentresAndAreas.C)
417  scalarField magAreas(mag(faceAreas));
418 
419  tmp<scalarField> tfaceFlatness(new scalarField(mesh.nFaces(), 1.0));
420  scalarField& faceFlatness = tfaceFlatness.ref();
421 
422 
423  forAll(fcs, facei)
424  {
425  const face& f = fcs[facei];
426 
427  if (f.size() > 3 && magAreas[facei] > rootVSmall)
428  {
429  const point& fc = fCtrs[facei];
430 
431  // Calculate the sum of magnitude of areas and compare to magnitude
432  // of sum of areas.
433 
434  scalar sumA = 0.0;
435 
436  forAll(f, fp)
437  {
438  const point& thisPoint = p[f[fp]];
439  const point& nextPoint = p[f.nextLabel(fp)];
440 
441  // Triangle around fc.
442  const vector n = 0.5*((nextPoint - thisPoint)^(fc - thisPoint));
443  sumA += mag(n);
444  }
445 
446  faceFlatness[facei] = magAreas[facei]/(sumA + rootVSmall);
447  }
448  }
449 
450  return tfaceFlatness;
451 }
452 
453 
455 (
456  const primitiveMesh& mesh,
457  const Vector<label>& meshD,
458  const vectorField& faceAreas,
459  const PackedBoolList& internalOrCoupledFace
460 )
461 {
462  // Determine number of dimensions and (for 2D) missing dimension
463  label nDims = 0;
464  label twoD = -1;
465  for (direction dir = 0; dir < vector::nComponents; dir++)
466  {
467  if (meshD[dir] == 1)
468  {
469  nDims++;
470  }
471  else
472  {
473  twoD = dir;
474  }
475  }
476 
477  tmp<scalarField> tcellDeterminant(new scalarField(mesh.nCells()));
478  scalarField& cellDeterminant = tcellDeterminant.ref();
479 
480  const cellList& c = mesh.cells();
481 
482  if (nDims == 1)
483  {
484  cellDeterminant = 1.0;
485  }
486  else
487  {
488  forAll(c, celli)
489  {
490  const labelList& curFaces = c[celli];
491 
492  // Calculate local normalisation factor
493  scalar avgArea = 0;
494 
495  label nInternalFaces = 0;
496 
497  forAll(curFaces, i)
498  {
499  if (internalOrCoupledFace[curFaces[i]])
500  {
501  avgArea += mag(faceAreas[curFaces[i]]);
502 
503  nInternalFaces++;
504  }
505  }
506 
507  if (nInternalFaces == 0)
508  {
509  cellDeterminant[celli] = 0;
510  }
511  else
512  {
513  avgArea /= nInternalFaces;
514 
515  symmTensor areaTensor(Zero);
516 
517  forAll(curFaces, i)
518  {
519  if (internalOrCoupledFace[curFaces[i]])
520  {
521  areaTensor += sqr(faceAreas[curFaces[i]]/avgArea);
522  }
523  }
524 
525  if (nDims == 2)
526  {
527  // Add the missing eigenvector (such that it does not
528  // affect the determinant)
529  if (twoD == 0)
530  {
531  areaTensor.xx() = 1;
532  }
533  else if (twoD == 1)
534  {
535  areaTensor.yy() = 1;
536  }
537  else
538  {
539  areaTensor.zz() = 1;
540  }
541  }
542 
543  cellDeterminant[celli] = mag(det(areaTensor));
544  }
545  }
546  }
547 
548  return tcellDeterminant;
549 }
550 
551 
553 (
554  const primitiveMesh& mesh,
555  const scalar closedThreshold,
556  const bool report
557 )
558 {
559  if (mesh.debug)
560  {
562  << "Checking whether the boundary is closed" << endl;
563  }
564 
565  const vectorField& areas = mesh.faceAreas();
566 
567  // Loop through all boundary faces and sum up the face area vectors.
568  // For a closed boundary, this should be zero in all vector components
569 
570  vector sumClosed(Zero);
571  scalar sumMagClosedBoundary = 0;
572 
573  for (label facei = mesh.nInternalFaces(); facei < areas.size(); facei++)
574  {
575  sumClosed += areas[facei];
576  sumMagClosedBoundary += mag(areas[facei]);
577  }
578 
579  reduce(sumClosed, sumOp<vector>());
580  reduce(sumMagClosedBoundary, sumOp<scalar>());
581 
582  vector openness = sumClosed/(sumMagClosedBoundary + vSmall);
583 
584  if (cmptMax(cmptMag(openness)) > closedThreshold)
585  {
586  if (report)
587  {
588  Info<< " ***Boundary openness " << openness
589  << " possible hole in boundary description."
590  << endl;
591  }
592 
593  return true;
594  }
595  else
596  {
597  if (report)
598  {
599  Info<< " Boundary openness " << openness << " OK."
600  << endl;
601  }
602 
603  return false;
604  }
605 }
606 
607 
609 (
610  const primitiveMesh& mesh,
611  const scalar closedThreshold,
612  const scalar aspectThreshold,
613  const bool report,
614  labelHashSet* setPtr,
615  labelHashSet* aspectSetPtr,
616  const Vector<label>& meshD
617 )
618 {
619  if (mesh.debug)
620  {
622  << "Checking whether cells are closed" << endl;
623  }
624 
625  const vectorField& faceAreas = mesh.faceAreas();
626  const scalarField& cellVolumes = mesh.cellVolumes();
627 
628  // Check that all cells labels are valid
629  const cellList& c = mesh.cells();
630 
631  label nErrorClosed = 0;
632 
633  forAll(c, cI)
634  {
635  const cell& curCell = c[cI];
636 
637  if (min(curCell) < 0 || max(curCell) > mesh.nFaces())
638  {
639  if (setPtr)
640  {
641  setPtr->insert(cI);
642  }
643 
644  nErrorClosed++;
645  }
646  }
647 
648  if (nErrorClosed > 0)
649  {
650  if (report)
651  {
652  Info<< " ***Cells with invalid face labels found, number of cells "
653  << nErrorClosed << endl;
654  }
655 
656  return true;
657  }
658 
659 
660  scalarField openness;
661  scalarField aspectRatio;
663  (
664  mesh,
665  meshD,
666  faceAreas,
667  cellVolumes,
668  openness,
669  aspectRatio
670  );
671 
672  label nOpen = 0;
673  scalar maxOpennessCell = max(openness);
674  label nAspect = 0;
675  scalar maxAspectRatio = max(aspectRatio);
676 
677  // Check the sums
678  forAll(openness, celli)
679  {
680  if (openness[celli] > closedThreshold)
681  {
682  if (setPtr)
683  {
684  setPtr->insert(celli);
685  }
686 
687  nOpen++;
688  }
689 
690  if (aspectRatio[celli] > aspectThreshold)
691  {
692  if (aspectSetPtr)
693  {
694  aspectSetPtr->insert(celli);
695  }
696 
697  nAspect++;
698  }
699  }
700 
701  reduce(nOpen, sumOp<label>());
702  reduce(maxOpennessCell, maxOp<scalar>());
703 
704  reduce(nAspect, sumOp<label>());
705  reduce(maxAspectRatio, maxOp<scalar>());
706 
707 
708  if (nOpen > 0)
709  {
710  if (report)
711  {
712  Info<< " ***Open cells found, max cell openness: "
713  << maxOpennessCell << ", number of open cells " << nOpen
714  << endl;
715  }
716 
717  return true;
718  }
719 
720  if (nAspect > 0)
721  {
722  if (report)
723  {
724  Info<< " ***High aspect ratio cells found, Max aspect ratio: "
725  << maxAspectRatio
726  << ", number of cells " << nAspect
727  << endl;
728  }
729 
730  return true;
731  }
732 
733  if (report)
734  {
735  Info<< " Max cell openness = " << maxOpennessCell << " OK." << nl
736  << " Max aspect ratio = " << maxAspectRatio << " OK."
737  << endl;
738  }
739 
740  return false;
741 }
742 
743 
745 (
746  const primitiveMesh& mesh,
747  const bool report,
748  labelHashSet* setPtr
749 )
750 {
751  if (mesh.debug)
752  {
753  InfoInFunction << "Checking face area magnitudes" << endl;
754  }
755 
756  const vectorField& faceAreas = mesh.faceAreas();
757  const scalarField magFaceAreas(mag(faceAreas));
758 
759  scalar minArea = great;
760  scalar maxArea = -great;
761 
762  forAll(magFaceAreas, facei)
763  {
764  if (magFaceAreas[facei] < vSmall)
765  {
766  if (setPtr)
767  {
768  setPtr->insert(facei);
769  }
770  }
771 
772  minArea = min(minArea, magFaceAreas[facei]);
773  maxArea = max(maxArea, magFaceAreas[facei]);
774  }
775 
776  reduce(minArea, minOp<scalar>());
777  reduce(maxArea, maxOp<scalar>());
778 
779  if (minArea < vSmall)
780  {
781  if (report)
782  {
783  Info<< " ***Zero or negative face area detected. "
784  "Minimum area: " << minArea << endl;
785  }
786 
787  return true;
788  }
789  else
790  {
791  if (report)
792  {
793  Info<< " Minimum face area = " << minArea
794  << ". Maximum face area = " << maxArea
795  << ". Face area magnitudes OK." << endl;
796  }
797 
798  return false;
799  }
800 }
801 
802 
804 (
805  const primitiveMesh& mesh,
806  const bool report,
807  labelHashSet* setPtr
808 )
809 {
810  if (mesh.debug)
811  {
812  InfoInFunction << "Checking cell volumes" << endl;
813  }
814 
815  const scalarField& vols = mesh.cellVolumes();
816  scalar minVolume = great;
817  scalar maxVolume = -great;
818 
819  label nNegVolCells = 0;
820 
821  forAll(vols, celli)
822  {
823  if (vols[celli] < vSmall)
824  {
825  if (setPtr)
826  {
827  setPtr->insert(celli);
828  }
829 
830  nNegVolCells++;
831  }
832 
833  minVolume = min(minVolume, vols[celli]);
834  maxVolume = max(maxVolume, vols[celli]);
835  }
836 
837  reduce(minVolume, minOp<scalar>());
838  reduce(maxVolume, maxOp<scalar>());
839  reduce(nNegVolCells, sumOp<label>());
840 
841  if (minVolume < vSmall)
842  {
843  if (report)
844  {
845  Info<< " ***Zero or negative cell volume detected. "
846  << "Minimum negative volume: " << minVolume
847  << ", Number of negative volume cells: " << nNegVolCells
848  << endl;
849  }
850 
851  return true;
852  }
853  else
854  {
855  if (report)
856  {
857  Info<< " Min volume = " << minVolume
858  << ". Max volume = " << maxVolume
859  << ". Total volume = " << gSum(vols)
860  << ". Cell volumes OK." << endl;
861  }
862 
863  return false;
864  }
865 }
866 
867 
869 (
870  const primitiveMesh& mesh,
871  const bool report,
872  const scalar minPyrVol,
873  labelHashSet* setPtr
874 )
875 {
876  if (mesh.debug)
877  {
878  InfoInFunction << "Checking face orientation" << endl;
879  }
880 
881  const pointField& points = mesh.points();
882  const vectorField& ctrs = mesh.cellCentres();
883 
884 
885  scalarField ownPyrVol;
886  scalarField neiPyrVol;
888  (
889  mesh,
890  points,
891  ctrs,
892  ownPyrVol,
893  neiPyrVol
894  );
895 
896 
897  label nErrorPyrs = 0;
898 
899  forAll(ownPyrVol, facei)
900  {
901  if (ownPyrVol[facei] < minPyrVol)
902  {
903  if (setPtr)
904  {
905  setPtr->insert(facei);
906  }
907 
908  nErrorPyrs++;
909  }
910 
911  if (mesh.isInternalFace(facei))
912  {
913  if (neiPyrVol[facei] < minPyrVol)
914  {
915  if (setPtr)
916  {
917  setPtr->insert(facei);
918  }
919  nErrorPyrs++;
920  }
921  }
922  }
923 
924  reduce(nErrorPyrs, sumOp<label>());
925 
926  if (nErrorPyrs > 0)
927  {
928  if (report)
929  {
930  Info<< " ***Error in face pyramids: "
931  << nErrorPyrs << " faces are incorrectly oriented."
932  << endl;
933  }
934 
935  return true;
936  }
937  else
938  {
939  if (report)
940  {
941  Info<< " Face pyramids OK." << endl;
942  }
943 
944  return false;
945  }
946 }
947 
948 
950 (
951  const primitiveMesh& mesh,
952  const bool report,
953  const scalar maxConcave,
954  labelHashSet* setPtr
955 )
956 {
957  if (mesh.debug)
958  {
959  InfoInFunction << "Checking face angles" << endl;
960  }
961 
962  if (maxConcave < -small || maxConcave > degToRad(180)+small)
963  {
965  << "maxConcave should be [0..180] degrees but is "
966  << radToDeg(maxConcave) << abort(FatalError);
967  }
968 
969  const scalar maxSin = Foam::sin(maxConcave);
970 
971  const pointField& points = mesh.points();
972  const vectorField& faceAreas = mesh.faceAreas();
973 
975  (
976  maxSin,
977  mesh,
978  points,
979  faceAreas
980  );
981  const scalarField& faceAngles = tfaceAngles();
982 
983  scalar maxEdgeSin = max(faceAngles);
984 
985  label nConcave = 0;
986 
987  forAll(faceAngles, facei)
988  {
989  if (faceAngles[facei] > small)
990  {
991  nConcave++;
992 
993  if (setPtr)
994  {
995  setPtr->insert(facei);
996  }
997  }
998  }
999 
1000  reduce(nConcave, sumOp<label>());
1001  reduce(maxEdgeSin, maxOp<scalar>());
1002 
1003  if (nConcave > 0)
1004  {
1005  if (report)
1006  {
1007  Info<< " *There are " << nConcave
1008  << " faces with concave angles between consecutive"
1009  << " edges. Max concave angle = "
1010  << radToDeg(Foam::asin(Foam::min(1.0, maxEdgeSin)))
1011  << " degrees." << endl;
1012  }
1013 
1014  return true;
1015  }
1016  else
1017  {
1018  if (report)
1019  {
1020  Info<< " All angles in faces OK." << endl;
1021  }
1022 
1023  return false;
1024  }
1025 }
1026 
1027 
1029 (
1030  const primitiveMesh& mesh,
1031  const bool report,
1032  const scalar warnFlatness,
1033  labelHashSet* setPtr
1034 )
1035 {
1036  if (mesh.debug)
1037  {
1038  InfoInFunction << "Checking face flatness" << endl;
1039  }
1040 
1041  if (warnFlatness < 0 || warnFlatness > 1)
1042  {
1044  << "warnFlatness should be [0..1] but is now " << warnFlatness
1045  << exit(FatalError);
1046  }
1047 
1048  const pointField& points = mesh.points();
1049  const vectorField& faceCentres = mesh.faceCentres();
1050  const vectorField& faceAreas = mesh.faceAreas();
1051  const faceList& fcs = mesh.faces();
1052 
1054  (
1055  mesh,
1056  points,
1057  faceCentres,
1058  faceAreas
1059  );
1060  const scalarField& faceFlatness = tfaceFlatness();
1061 
1062  scalarField magAreas(mag(faceAreas));
1063 
1064  scalar minFlatness = great;
1065  scalar sumFlatness = 0;
1066  label nSummed = 0;
1067  label nWarped = 0;
1068 
1069  forAll(faceFlatness, facei)
1070  {
1071  if (fcs[facei].size() > 3 && magAreas[facei] > vSmall)
1072  {
1073  sumFlatness += faceFlatness[facei];
1074  nSummed++;
1075 
1076  minFlatness = min(minFlatness, faceFlatness[facei]);
1077 
1078  if (faceFlatness[facei] < warnFlatness)
1079  {
1080  nWarped++;
1081 
1082  if (setPtr)
1083  {
1084  setPtr->insert(facei);
1085  }
1086  }
1087  }
1088  }
1089 
1090 
1091  reduce(nWarped, sumOp<label>());
1092  reduce(minFlatness, minOp<scalar>());
1093 
1094  reduce(nSummed, sumOp<label>());
1095  reduce(sumFlatness, sumOp<scalar>());
1096 
1097  if (report)
1098  {
1099  if (nSummed > 0)
1100  {
1101  Info<< " Face flatness (1 = flat, 0 = butterfly) : min = "
1102  << minFlatness << " average = " << sumFlatness / nSummed
1103  << endl;
1104  }
1105  }
1106 
1107 
1108  if (nWarped> 0)
1109  {
1110  if (report)
1111  {
1112  Info<< " *There are " << nWarped
1113  << " faces with ratio between projected and actual area < "
1114  << warnFlatness << endl;
1115 
1116  Info<< " Minimum ratio (minimum flatness, maximum warpage) = "
1117  << minFlatness << endl;
1118  }
1119 
1120  return true;
1121  }
1122  else
1123  {
1124  if (report)
1125  {
1126  Info<< " All face flatness OK." << endl;
1127  }
1128 
1129  return false;
1130  }
1131 }
1132 
1133 
1135 (
1136  const primitiveMesh& mesh,
1137  const scalar planarCosAngle,
1138  const bool report,
1139  labelHashSet* setPtr
1140 )
1141 {
1142  if (mesh.debug)
1143  {
1144  InfoInFunction << "Checking for concave cells" << endl;
1145  }
1146 
1147  const vectorField& fAreas = mesh.faceAreas();
1148  const pointField& fCentres = mesh.faceCentres();
1149  const cellList& c = mesh.cells();
1150  const labelList& fOwner = mesh.faceOwner();
1151 
1152  label nConcaveCells = 0;
1153 
1154  forAll(c, celli)
1155  {
1156  const cell& cFaces = c[celli];
1157 
1158  bool concave = false;
1159 
1160  forAll(cFaces, i)
1161  {
1162  if (concave)
1163  {
1164  break;
1165  }
1166 
1167  const label fI = cFaces[i];
1168 
1169  const point& fC = fCentres[fI];
1170 
1171  vector fN = fAreas[fI];
1172  fN /= max(mag(fN), vSmall);
1173 
1174  // Flip normal if required so that it is always pointing out of
1175  // the cell
1176  if (fOwner[fI] != celli)
1177  {
1178  fN *= -1;
1179  }
1180 
1181  // Is the centre of any other face of the cell on the
1182  // wrong side of the plane of this face?
1183 
1184  forAll(cFaces, j)
1185  {
1186  if (j != i)
1187  {
1188  const label fJ = cFaces[j];
1189 
1190  const point& pt = fCentres[fJ];
1191 
1192  // If the cell is concave, the point will be on the
1193  // positive normal side of the plane of f, defined by
1194  // its centre and normal, and the angle between (pt -
1195  // fC) and fN will be less than 90 degrees, so the dot
1196  // product will be positive.
1197 
1198  vector pC = (pt - fC);
1199  pC /= max(mag(pC), vSmall);
1200 
1201  if ((pC & fN) > -planarCosAngle)
1202  {
1203  // Concave or planar face
1204 
1205  concave = true;
1206 
1207  if (setPtr)
1208  {
1209  setPtr->insert(celli);
1210  }
1211 
1212  nConcaveCells++;
1213 
1214  break;
1215  }
1216  }
1217  }
1218  }
1219  }
1220 
1221  reduce(nConcaveCells, sumOp<label>());
1222 
1223  if (nConcaveCells > 0)
1224  {
1225  if (report)
1226  {
1227  Info<< " ***Concave cells (using face planes) found,"
1228  << " number of cells: " << nConcaveCells << endl;
1229  }
1230 
1231  return true;
1232  }
1233  else
1234  {
1235  if (report)
1236  {
1237  Info<< " Concave cell check OK." << endl;
1238  }
1239 
1240  return false;
1241  }
1242 
1243  return false;
1244 }
1245 
1246 
1248 (
1249  const primitiveMesh& mesh,
1250  const bool report,
1251  labelHashSet* setPtr
1252 )
1253 {
1254  if (mesh.debug)
1255  {
1256  InfoInFunction << "Checking face ordering" << endl;
1257  }
1258 
1259  // Check whether internal faces are ordered in the upper triangular order
1260  const labelList& own = mesh.faceOwner();
1261  const labelList& nei = mesh.faceNeighbour();
1262  const cellList& c = mesh.cells();
1263  const label internal = mesh.nInternalFaces();
1264 
1265  // Has error occurred?
1266  bool error = false;
1267 
1268  // Have multiple faces been detected?
1269  label nMultipleCells = false;
1270 
1271  // Loop through faceCells once more and make sure that for internal cell
1272  // the first label is smaller
1273  for (label facei = 0; facei < internal; facei++)
1274  {
1275  if (own[facei] >= nei[facei])
1276  {
1277  error = true;
1278 
1279  if (setPtr)
1280  {
1281  setPtr->insert(facei);
1282  }
1283  }
1284  }
1285 
1286  // Loop through all cells. For each cell, find the face that is internal
1287  // and add it to the check list (upper triangular order).
1288  // Once the list is completed, check it against the faceCell list
1289 
1290  forAll(c, celli)
1291  {
1292  const labelList& curFaces = c[celli];
1293 
1294  // Neighbouring cells
1295  SortableList<label> nbr(curFaces.size());
1296 
1297  forAll(curFaces, i)
1298  {
1299  label facei = curFaces[i];
1300 
1301  if (facei >= mesh.nInternalFaces())
1302  {
1303  // Sort last
1304  nbr[i] = labelMax;
1305  }
1306  else
1307  {
1308  label nbrCelli = nei[facei];
1309 
1310  if (nbrCelli == celli)
1311  {
1312  nbrCelli = own[facei];
1313  }
1314 
1315  if (celli < nbrCelli)
1316  {
1317  // celli is master
1318  nbr[i] = nbrCelli;
1319  }
1320  else
1321  {
1322  // nbrCell is master. Let it handle this face.
1323  nbr[i] = labelMax;
1324  }
1325  }
1326  }
1327 
1328  nbr.sort();
1329 
1330  // Now nbr holds the cellCells in incremental order. Check:
1331  // - neighbouring cells appear only once. Since nbr is sorted this
1332  // is simple check on consecutive elements
1333  // - faces indexed in same order as nbr are incrementing as well.
1334 
1335  label prevCell = nbr[0];
1336  label prevFace = curFaces[nbr.indices()[0]];
1337 
1338  bool hasMultipleFaces = false;
1339 
1340  for (label i = 1; i < nbr.size(); i++)
1341  {
1342  const label thisCell = nbr[i];
1343  const label thisFace = curFaces[nbr.indices()[i]];
1344 
1345  if (thisCell == labelMax)
1346  {
1347  break;
1348  }
1349 
1350  if (thisCell == prevCell)
1351  {
1352  hasMultipleFaces = true;
1353 
1354  if (setPtr)
1355  {
1356  setPtr->insert(prevFace);
1357  setPtr->insert(thisFace);
1358  }
1359  }
1360  else if (thisFace < prevFace)
1361  {
1362  error = true;
1363 
1364  if (setPtr)
1365  {
1366  setPtr->insert(thisFace);
1367  }
1368  }
1369 
1370  prevCell = thisCell;
1371  prevFace = thisFace;
1372  }
1373 
1374  if (hasMultipleFaces)
1375  {
1376  nMultipleCells++;
1377  }
1378  }
1379 
1380  reduce(error, orOp<bool>());
1381  reduce(nMultipleCells, sumOp<label>());
1382 
1383  if ((report) && nMultipleCells > 0)
1384  {
1385  Info<< " <<Found " << nMultipleCells
1386  << " neighbouring cells with multiple in between faces." << endl;
1387  }
1388 
1389  if (error)
1390  {
1391  if (report)
1392  {
1393  Info<< " ***Faces not in upper triangular order." << endl;
1394  }
1395 
1396  return true;
1397  }
1398  else
1399  {
1400  if (report)
1401  {
1402  Info<< " Upper triangular ordering OK." << endl;
1403  }
1404 
1405  return false;
1406  }
1407 }
1408 
1409 
1411 (
1412  const primitiveMesh& mesh,
1413  const bool report,
1414  labelHashSet* setPtr
1415 )
1416 {
1417  if (mesh.debug)
1418  {
1419  InfoInFunction << "Checking topological cell openness" << endl;
1420  }
1421 
1422  label nOpenCells = 0;
1423 
1424  const faceList& f = mesh.faces();
1425  const cellList& c = mesh.cells();
1426 
1427  forAll(c, celli)
1428  {
1429  const labelList& curFaces = c[celli];
1430 
1431  const edgeList cellEdges = c[celli].edges(f);
1432 
1433  labelList edgeUsage(cellEdges.size(), 0);
1434 
1435  forAll(curFaces, facei)
1436  {
1437  const edgeList curFaceEdges = f[curFaces[facei]].edges();
1438 
1439  forAll(curFaceEdges, faceEdgeI)
1440  {
1441  const edge& curEdge = curFaceEdges[faceEdgeI];
1442 
1443  forAll(cellEdges, cellEdgeI)
1444  {
1445  if (cellEdges[cellEdgeI] == curEdge)
1446  {
1447  edgeUsage[cellEdgeI]++;
1448  break;
1449  }
1450  }
1451  }
1452  }
1453 
1454  edgeList singleEdges(cellEdges.size());
1455  label nSingleEdges = 0;
1456 
1457  forAll(edgeUsage, edgeI)
1458  {
1459  if (edgeUsage[edgeI] == 1)
1460  {
1461  singleEdges[nSingleEdges] = cellEdges[edgeI];
1462  nSingleEdges++;
1463  }
1464  else if (edgeUsage[edgeI] != 2)
1465  {
1466  if (setPtr)
1467  {
1468  setPtr->insert(celli);
1469  }
1470  }
1471  }
1472 
1473  if (nSingleEdges > 0)
1474  {
1475  if (setPtr)
1476  {
1477  setPtr->insert(celli);
1478  }
1479 
1480  nOpenCells++;
1481  }
1482  }
1483 
1484  reduce(nOpenCells, sumOp<label>());
1485 
1486  if (nOpenCells > 0)
1487  {
1488  if (report)
1489  {
1490  Info<< " ***Open cells found, number of cells: " << nOpenCells
1491  << ". This problem may be fixable using the zipUpMesh utility."
1492  << endl;
1493  }
1494 
1495  return true;
1496  }
1497  else
1498  {
1499  if (report)
1500  {
1501  Info<< " Topological cell zip-up check OK." << endl;
1502  }
1503 
1504  return false;
1505  }
1506 }
1507 
1508 
1510 (
1511  const primitiveMesh& mesh,
1512  const bool report,
1513  labelHashSet* setPtr
1514 )
1515 {
1516  if (mesh.debug)
1517  {
1518  InfoInFunction << "Checking face vertices" << endl;
1519  }
1520 
1521  // Check that all vertex labels are valid
1522  const faceList& f = mesh.faces();
1523 
1524  label nErrorFaces = 0;
1525 
1526  forAll(f, fI)
1527  {
1528  const face& curFace = f[fI];
1529 
1530  if (min(curFace) < 0 || max(curFace) > mesh.nPoints())
1531  {
1532  if (setPtr)
1533  {
1534  setPtr->insert(fI);
1535  }
1536 
1537  nErrorFaces++;
1538  }
1539 
1540  // Uniqueness of vertices
1541  labelHashSet facePoints(2*curFace.size());
1542 
1543  forAll(curFace, fp)
1544  {
1545  const bool inserted = facePoints.insert(curFace[fp]);
1546 
1547  if (!inserted)
1548  {
1549  if (setPtr)
1550  {
1551  setPtr->insert(fI);
1552  }
1553 
1554  nErrorFaces++;
1555  }
1556  }
1557  }
1558 
1559  reduce(nErrorFaces, sumOp<label>());
1560 
1561  if (nErrorFaces > 0)
1562  {
1563  if (report)
1564  {
1565  Info<< " ***Faces with invalid vertex labels found, "
1566  << " number of faces: " << nErrorFaces << endl;
1567  }
1568 
1569  return true;
1570  }
1571  else
1572  {
1573  if (report)
1574  {
1575  Info<< " Face vertices OK." << endl;
1576  }
1577 
1578  return false;
1579  }
1580 }
1581 
1582 
1584 (
1585  const primitiveMesh& mesh,
1586  const bool report,
1587  labelHashSet* setPtr
1588 )
1589 {
1590  if (mesh.debug)
1591  {
1592  InfoInFunction << "Checking points" << endl;
1593  }
1594 
1595  label nFaceErrors = 0;
1596  label nCellErrors = 0;
1597 
1598  const labelListList& pf = mesh.pointFaces();
1599 
1600  forAll(pf, pointi)
1601  {
1602  if (pf[pointi].empty())
1603  {
1604  if (setPtr)
1605  {
1606  setPtr->insert(pointi);
1607  }
1608 
1609  nFaceErrors++;
1610  }
1611  }
1612 
1613 
1614  forAll(pf, pointi)
1615  {
1616  const labelList& pc = mesh.pointCells(pointi);
1617 
1618  if (pc.empty())
1619  {
1620  if (setPtr)
1621  {
1622  setPtr->insert(pointi);
1623  }
1624 
1625  nCellErrors++;
1626  }
1627  }
1628 
1629  reduce(nFaceErrors, sumOp<label>());
1630  reduce(nCellErrors, sumOp<label>());
1631 
1632  if (nFaceErrors > 0 || nCellErrors > 0)
1633  {
1634  if (report)
1635  {
1636  Info<< " ***Unused points found in the mesh, "
1637  "number unused by faces: " << nFaceErrors
1638  << " number unused by cells: " << nCellErrors
1639  << endl;
1640  }
1641 
1642  return true;
1643  }
1644  else
1645  {
1646  if (report)
1647  {
1648  Info<< " Point usage OK." << endl;
1649  }
1650 
1651  return false;
1652  }
1653 }
1654 
1655 
1657 (
1658  const primitiveMesh& mesh,
1659  const label facei,
1660  const Map<label>& nCommonPoints,
1661  label& nBaffleFaces,
1662  labelHashSet* setPtr
1663 )
1664 {
1665  bool error = false;
1666 
1667  forAllConstIter(Map<label>, nCommonPoints, iter)
1668  {
1669  const label nbFacei = iter.key();
1670  const label nCommon = iter();
1671 
1672  const face& curFace = mesh.faces()[facei];
1673  const face& nbFace = mesh.faces()[nbFacei];
1674 
1675  if (nCommon == nbFace.size() || nCommon == curFace.size())
1676  {
1677  if (nbFace.size() != curFace.size())
1678  {
1679  error = true;
1680  }
1681  else
1682  {
1683  nBaffleFaces++;
1684  }
1685 
1686  if (setPtr)
1687  {
1688  setPtr->insert(facei);
1689  setPtr->insert(nbFacei);
1690  }
1691  }
1692  }
1693 
1694  return error;
1695 }
1696 
1697 
1699 (
1700  const primitiveMesh& mesh,
1701  const label facei,
1702  const Map<label>& nCommonPoints,
1703  labelHashSet* setPtr
1704 )
1705 {
1706  bool error = false;
1707 
1708  forAllConstIter(Map<label>, nCommonPoints, iter)
1709  {
1710  const label nbFacei = iter.key();
1711  const label nCommon = iter();
1712 
1713  const face& curFace = mesh.faces()[facei];
1714  const face& nbFace = mesh.faces()[nbFacei];
1715 
1716  if
1717  (
1718  nCommon >= 2
1719  && nCommon != nbFace.size()
1720  && nCommon != curFace.size()
1721  )
1722  {
1723  forAll(curFace, fp)
1724  {
1725  // Get the index in the neighbouring face shared with curFace
1726  label nb = findIndex(nbFace, curFace[fp]);
1727 
1728  if (nb != -1)
1729  {
1730 
1731  // Check the whole face from nb onwards for shared vertices
1732  // with neighbouring face. Rule is that any shared vertices
1733  // should be consecutive on both faces i.e. if they are
1734  // vertices fp,fp+1,fp+2 on one face they should be
1735  // vertices nb, nb+1, nb+2 (or nb+2, nb+1, nb) on the
1736  // other face.
1737 
1738 
1739  // Vertices before and after on curFace
1740  const label fpPlus1 = curFace.fcIndex(fp);
1741  const label fpMin1 = curFace.rcIndex(fp);
1742 
1743  // Vertices before and after on nbFace
1744  const label nbPlus1 = nbFace.fcIndex(nb);
1745  const label nbMin1 = nbFace.rcIndex(nb);
1746 
1747  // Find order of walking by comparing next points on both
1748  // faces.
1749  label curInc = labelMax;
1750  label nbInc = labelMax;
1751 
1752  if (nbFace[nbPlus1] == curFace[fpPlus1])
1753  {
1754  curInc = 1;
1755  nbInc = 1;
1756  }
1757  else if (nbFace[nbPlus1] == curFace[fpMin1])
1758  {
1759  curInc = -1;
1760  nbInc = 1;
1761  }
1762  else if (nbFace[nbMin1] == curFace[fpMin1])
1763  {
1764  curInc = -1;
1765  nbInc = -1;
1766  }
1767  else
1768  {
1769  curInc = 1;
1770  nbInc = -1;
1771  }
1772 
1773 
1774  // Pass1: loop until start of common vertices found.
1775  label curNb = nb;
1776  label curFp = fp;
1777 
1778  do
1779  {
1780  curFp += curInc;
1781 
1782  if (curFp >= curFace.size())
1783  {
1784  curFp = 0;
1785  }
1786  else if (curFp < 0)
1787  {
1788  curFp = curFace.size()-1;
1789  }
1790 
1791  curNb += nbInc;
1792 
1793  if (curNb >= nbFace.size())
1794  {
1795  curNb = 0;
1796  }
1797  else if (curNb < 0)
1798  {
1799  curNb = nbFace.size()-1;
1800  }
1801  } while (curFace[curFp] == nbFace[curNb]);
1802 
1803 
1804  // Pass2: check equality walking from curFp, curNb
1805  // in opposite order.
1806 
1807  curInc = -curInc;
1808  nbInc = -nbInc;
1809 
1810  for (label commonI = 0; commonI < nCommon; commonI++)
1811  {
1812  curFp += curInc;
1813 
1814  if (curFp >= curFace.size())
1815  {
1816  curFp = 0;
1817  }
1818  else if (curFp < 0)
1819  {
1820  curFp = curFace.size()-1;
1821  }
1822 
1823  curNb += nbInc;
1824 
1825  if (curNb >= nbFace.size())
1826  {
1827  curNb = 0;
1828  }
1829  else if (curNb < 0)
1830  {
1831  curNb = nbFace.size()-1;
1832  }
1833 
1834  if (curFace[curFp] != nbFace[curNb])
1835  {
1836  if (setPtr)
1837  {
1838  setPtr->insert(facei);
1839  setPtr->insert(nbFacei);
1840  }
1841 
1842  error = true;
1843 
1844  break;
1845  }
1846  }
1847 
1848 
1849  // Done the curFace - nbFace combination.
1850  break;
1851  }
1852  }
1853  }
1854  }
1855 
1856  return error;
1857 }
1858 
1859 
1861 (
1862  const primitiveMesh& mesh,
1863  const bool report,
1864  labelHashSet* setPtr
1865 )
1866 {
1867  if (mesh.debug)
1868  {
1869  InfoInFunction << "Checking face-face connectivity" << endl;
1870  }
1871 
1872  const labelListList& pf = mesh.pointFaces();
1873 
1874  label nBaffleFaces = 0;
1875  label nErrorDuplicate = 0;
1876  label nErrorOrder = 0;
1877  Map<label> nCommonPoints(100);
1878 
1879  for (label facei = 0; facei < mesh.nFaces(); facei++)
1880  {
1881  const face& curFace = mesh.faces()[facei];
1882 
1883  // Calculate number of common points between current facei and
1884  // neighbouring face. Store on map.
1885  nCommonPoints.clear();
1886 
1887  forAll(curFace, fp)
1888  {
1889  const label pointi = curFace[fp];
1890  const labelList& nbs = pf[pointi];
1891 
1892  forAll(nbs, nbI)
1893  {
1894  const label nbFacei = nbs[nbI];
1895 
1896  if (facei < nbFacei)
1897  {
1898  // Only check once for each combination of two faces.
1899 
1900  Map<label>::iterator fnd = nCommonPoints.find(nbFacei);
1901 
1902  if (fnd == nCommonPoints.end())
1903  {
1904  // First common vertex found.
1905  nCommonPoints.insert(nbFacei, 1);
1906  }
1907  else
1908  {
1909  fnd()++;
1910  }
1911  }
1912  }
1913  }
1914 
1915  // Perform various checks on common points
1916 
1917  // Check all vertices shared (duplicate point)
1918  if
1919  (
1921  (
1922  mesh,
1923  facei,
1924  nCommonPoints,
1925  nBaffleFaces,
1926  setPtr
1927  )
1928  )
1929  {
1930  nErrorDuplicate++;
1931  }
1932 
1933  // Check common vertices are consecutive on both faces
1934  if (checkCommonOrder(mesh, facei, nCommonPoints, setPtr))
1935  {
1936  nErrorOrder++;
1937  }
1938  }
1939 
1940  reduce(nBaffleFaces, sumOp<label>());
1941  reduce(nErrorDuplicate, sumOp<label>());
1942  reduce(nErrorOrder, sumOp<label>());
1943 
1944  if (nBaffleFaces)
1945  {
1946  Info<< " Number of identical duplicate faces (baffle faces): "
1947  << nBaffleFaces << endl;
1948  }
1949 
1950  if (nErrorDuplicate > 0 || nErrorOrder > 0)
1951  {
1952  // These are actually warnings, not errors.
1953  if (nErrorDuplicate > 0)
1954  {
1955  Info<< " <<Number of duplicate (not baffle) faces found: "
1956  << nErrorDuplicate
1957  << ". This might indicate a problem." << endl;
1958  }
1959 
1960  if (nErrorOrder > 0)
1961  {
1962  Info<< " <<Number of faces with non-consecutive shared points: "
1963  << nErrorOrder << ". This might indicate a problem." << endl;
1964  }
1965 
1966  return false; // return true;
1967  }
1968  else
1969  {
1970  if (report)
1971  {
1972  Info<< " Face-face connectivity OK." << endl;
1973  }
1974 
1975  return false;
1976  }
1977 }
1978 
1979 
1980 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:167
void clear()
Clear all entries from table.
Definition: HashTable.C:542
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
A bit-packed bool list.
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: SortableList.H:55
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
Definition: SortableList.H:96
void sort()
(stable) sort the list (if changed after construction time)
Definition: SortableList.C:112
const Cmpt & xx() const
Definition: SymmTensorI.H:87
const Cmpt & zz() const
Definition: SymmTensorI.H:117
const Cmpt & yy() const
Definition: SymmTensorI.H:105
label rcIndex(const label i) const
Return the reverse circular index, i.e. the previous index.
Definition: UListI.H:65
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:60
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:71
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:75
label nCells() const
label nPoints() const
const vectorField & faceCentres() const
virtual const faceList & faces() const =0
Return faces.
const labelListList & pointCells() const
const scalarField & cellVolumes() const
const vectorField & cellCentres() const
virtual const labelList & faceOwner() const =0
Face face-owner addressing.
label nInternalFaces() const
label nFaces() const
const labelListList & pointFaces() const
virtual const labelList & faceNeighbour() const =0
Face face-neighbour addressing.
virtual const pointField & points() const =0
Return mesh points.
const vectorField & faceAreas() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
const cellList & cells() const
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:181
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
volScalarField scalarField(fieldObject, mesh)
const pointField & points
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define InfoInFunction
Report an information message using Foam::Info.
const dimensionedScalar c
Speed of light in a vacuum.
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)
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.
bool checkFacePyramids(const bool report, const scalar minPyrVol, const polyMesh &, const vectorField &cellCentres, const pointField &p, const labelList &checkFaces, const List< labelPair > &baffles, labelHashSet *)
Check face pyramid volumes.
tmp< scalarField > faceOrthogonality(const polyMesh &mesh, const vectorField &fAreas, const vectorField &cellCtrs)
Generate orthogonality field. (1 for fully orthogonal, < 1 for.
Definition: polyMeshCheck.C:34
tmp< scalarField > faceSkewness(const polyMesh &mesh, const pointField &points, const vectorField &fCtrs, const vectorField &fAreas, const vectorField &cellCtrs)
Generate skewness field.
Definition: polyMeshCheck.C:89
bool checkFaceFaces(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check face-face connectivity.
bool checkUpperTriangular(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check face ordering.
bool checkConcaveCells(const primitiveMesh &mesh, const scalar planarCosAngle, const bool report=false, labelHashSet *setPtr=nullptr)
Check for concave cells by the planes of faces.
bool checkFaceAngles(const bool report, const scalar maxConcave, const polyMesh &mesh, const vectorField &faceAreas, const pointField &p, const labelList &checkFaces, labelHashSet *setPtr)
Check convexity of angles in a face. See primitiveMesh for explanation.
bool checkDuplicateFaces(const primitiveMesh &mesh, const label, const Map< label > &, label &nBaffleFaces, labelHashSet *)
Check if all points on face are shared with another face.
bool checkFaceVertices(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check uniqueness of face vertices.
scalar boundaryFaceSkewness(const primitiveMesh &mesh, const pointField &p, const vectorField &fCtrs, const vectorField &fAreas, const label facei, const point &ownCc)
Skewness of single boundary face.
bool checkClosedCells(const primitiveMesh &mesh, const scalar closedThreshold, const scalar aspectThreshold, const bool report=false, labelHashSet *setPtr=nullptr, labelHashSet *highAspectSetPtr=nullptr, const Vector< label > &solutionD=Vector< label >::one)
Check cells for closedness.
bool checkCommonOrder(const primitiveMesh &mesh, const label, const Map< label > &, labelHashSet *)
Check that shared points are in consecutive order.
void facePyramidVolume(const primitiveMesh &mesh, const pointField &points, const vectorField &cellCtrs, scalarField &ownPyrVol, scalarField &neiPyrVol)
Generate face pyramid volume fields.
tmp< scalarField > cellDeterminant(const primitiveMesh &mesh, const Vector< label > &directions, const vectorField &faceAreas, const PackedBoolList &internalOrCoupledFace)
Generate cell determinant field.
tmp< scalarField > faceFlatness(const primitiveMesh &mesh, const pointField &p, const vectorField &fCtrs, const vectorField &faceAreas)
Generate face flatness field. Compares the individual triangles'.
bool checkClosedBoundary(const primitiveMesh &mesh, const scalar closedThreshold, const bool report=false)
Check boundary for closedness.
bool checkFaceFlatness(const bool report, const scalar minFlatness, const polyMesh &, const vectorField &faceAreas, const vectorField &faceCentres, const pointField &p, const labelList &checkFaces, labelHashSet *setPtr)
Check for face areas v.s. sum of face-triangle (from face-centre.
bool checkCellVolumes(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check for negative cell volumes.
bool checkFaceAreas(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check for negative face areas.
bool checkPoints(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check for unused points.
bool checkCellsZipUp(const primitiveMesh &mesh, const bool report=false, labelHashSet *setPtr=nullptr)
Check cell zip-up.
pyramid< point, const point &, const face & > pyramidPointFaceRef
dimensionedScalar det(const dimensionedSphericalTensor &dt)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
dimensionedScalar asin(const dimensionedScalar &ds)
Type gSum(const FieldField< Field, Type > &f)
scalar radToDeg(const scalar rad)
Convert radians to degrees.
scalar degToRad(const scalar deg)
Convert degrees to radians.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
errorManip< error > abort(error &err)
Definition: errorManip.H:131
dimensionedScalar sin(const dimensionedScalar &ds)
messageStream Info
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
dimensioned< scalar > mag(const dimensioned< Type > &)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
dimensionSet cmptMag(const dimensionSet &)
Definition: dimensionSet.C:296
void cmptMax(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
static const label labelMax
Definition: label.H:62
Cmpt cmptSum(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:507
static const char nl
Definition: Ostream.H:266
dimensionedTensor skew(const dimensionedTensor &dt)
uint8_t direction
Definition: direction.H:45
labelList f(nPoints)
volScalarField & p
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:112