1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "polyMeshGeometry.H"
28 #include "pyramidPointFaceRef.H"
29 #include "syncTools.H"
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 defineTypeNameAndDebug(polyMeshGeometry, 0);
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 void Foam::polyMeshGeometry::updateFaceCentresAndAreas
46 const labelList& changedFaces
49 const faceList& fs = mesh_.faces();
51 forAll(changedFaces, i)
53 label facei = changedFaces[i];
55 const labelList& f = fs[facei];
56 label nPoints = f.size();
58 // If the face is a triangle, do a direct calculation for efficiency
59 // and to avoid round-off error-related problems
62 faceCentres_[facei] = (1.0/3.0)*(p[f[0]] + p[f[1]] + p[f[2]]);
63 faceAreas_[facei] = 0.5*((p[f[1]] - p[f[0]])^(p[f[2]] - p[f[0]]));
67 vector sumN = vector::zero;
69 vector sumAc = vector::zero;
71 point fCentre = p[f[0]];
72 for (label pi = 1; pi < nPoints; pi++)
79 for (label pi = 0; pi < nPoints; pi++)
81 const point& nextPoint = p[f[(pi + 1) % nPoints]];
83 vector c = p[f[pi]] + nextPoint + fCentre;
84 vector n = (nextPoint - p[f[pi]])^(fCentre - p[f[pi]]);
92 faceCentres_[facei] = (1.0/3.0)*sumAc/(sumA + VSMALL);
93 faceAreas_[facei] = 0.5*sumN;
99 void Foam::polyMeshGeometry::updateCellCentresAndVols
101 const labelList& changedCells,
102 const labelList& changedFaces
105 // Clear the fields for accumulation
106 UIndirectList<vector>(cellCentres_, changedCells) = vector::zero;
107 UIndirectList<scalar>(cellVolumes_, changedCells) = 0.0;
109 const labelList& own = mesh_.faceOwner();
110 const labelList& nei = mesh_.faceNeighbour();
112 // first estimate the approximate cell centre as the average of face centres
114 vectorField cEst(mesh_.nCells());
115 UIndirectList<vector>(cEst, changedCells) = vector::zero;
116 scalarField nCellFaces(mesh_.nCells());
117 UIndirectList<scalar>(nCellFaces, changedCells) = 0.0;
119 forAll(changedFaces, i)
121 label faceI = changedFaces[i];
122 cEst[own[faceI]] += faceCentres_[faceI];
123 nCellFaces[own[faceI]] += 1;
125 if (mesh_.isInternalFace(faceI))
127 cEst[nei[faceI]] += faceCentres_[faceI];
128 nCellFaces[nei[faceI]] += 1;
132 forAll(changedCells, i)
134 label cellI = changedCells[i];
135 cEst[cellI] /= nCellFaces[cellI];
138 forAll(changedFaces, i)
140 label faceI = changedFaces[i];
142 // Calculate 3*face-pyramid volume
145 faceAreas_[faceI] & (faceCentres_[faceI] - cEst[own[faceI]]),
149 // Calculate face-pyramid centre
150 vector pc = (3.0/4.0)*faceCentres_[faceI] + (1.0/4.0)*cEst[own[faceI]];
152 // Accumulate volume-weighted face-pyramid centre
153 cellCentres_[own[faceI]] += pyr3Vol*pc;
155 // Accumulate face-pyramid volume
156 cellVolumes_[own[faceI]] += pyr3Vol;
158 if (mesh_.isInternalFace(faceI))
160 // Calculate 3*face-pyramid volume
163 faceAreas_[faceI] & (cEst[nei[faceI]] - faceCentres_[faceI]),
167 // Calculate face-pyramid centre
169 (3.0/4.0)*faceCentres_[faceI]
170 + (1.0/4.0)*cEst[nei[faceI]];
172 // Accumulate volume-weighted face-pyramid centre
173 cellCentres_[nei[faceI]] += pyr3Vol*pc;
175 // Accumulate face-pyramid volume
176 cellVolumes_[nei[faceI]] += pyr3Vol;
180 forAll(changedCells, i)
182 label cellI = changedCells[i];
184 cellCentres_[cellI] /= cellVolumes_[cellI] + VSMALL;
185 cellVolumes_[cellI] *= (1.0/3.0);
190 Foam::labelList Foam::polyMeshGeometry::affectedCells
192 const polyMesh& mesh,
193 const labelList& changedFaces
196 const labelList& own = mesh.faceOwner();
197 const labelList& nei = mesh.faceNeighbour();
199 labelHashSet affectedCells(2*changedFaces.size());
201 forAll(changedFaces, i)
203 label faceI = changedFaces[i];
205 affectedCells.insert(own[faceI]);
207 if (mesh.isInternalFace(faceI))
209 affectedCells.insert(nei[faceI]);
212 return affectedCells.toc();
216 Foam::scalar Foam::polyMeshGeometry::checkNonOrtho
218 const polyMesh& mesh,
220 const scalar severeNonorthogonalityThreshold,
222 const vector& s, // face area vector
223 const vector& d, // cc-cc vector
225 label& severeNonOrth,
230 scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
232 if (dDotS < severeNonorthogonalityThreshold)
236 if (mesh.isInternalFace(faceI))
238 nei = mesh.faceNeighbour()[faceI];
245 // Severe non-orthogonality but mesh still OK
246 Pout<< "Severe non-orthogonality for face " << faceI
247 << " between cells " << mesh.faceOwner()[faceI]
250 << ::acos(dDotS)/mathematicalConstant::pi*180.0
258 // Non-orthogonality greater than 90 deg
263 "polyMeshGeometry::checkFaceDotProduct"
264 "(const bool, const scalar, const labelList&"
266 ) << "Severe non-orthogonality detected for face "
268 << " between cells " << mesh.faceOwner()[faceI]
271 << ::acos(dDotS)/mathematicalConstant::pi*180.0
280 setPtr->insert(faceI);
287 Foam::scalar Foam::polyMeshGeometry::calcSkewness
294 scalar dOwn = mag(fc - ownCc);
295 scalar dNei = mag(fc - neiCc);
297 point faceIntersection =
298 ownCc*dNei/(dOwn+dNei+VSMALL)
299 + neiCc*dOwn/(dOwn+dNei+VSMALL);
302 mag(fc - faceIntersection)
310 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
312 // Construct from components
313 Foam::polyMeshGeometry::polyMeshGeometry(const polyMesh& mesh)
321 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
324 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
326 //- Take over properties from mesh
327 void Foam::polyMeshGeometry::correct()
329 faceAreas_ = mesh_.faceAreas();
330 faceCentres_ = mesh_.faceCentres();
331 cellCentres_ = mesh_.cellCentres();
332 cellVolumes_ = mesh_.cellVolumes();
336 //- Recalculate on selected faces
337 void Foam::polyMeshGeometry::correct
340 const labelList& changedFaces
343 // Update face quantities
344 updateFaceCentresAndAreas(p, changedFaces);
345 // Update cell quantities from face quantities
346 updateCellCentresAndVols(affectedCells(mesh_, changedFaces), changedFaces);
350 bool Foam::polyMeshGeometry::checkFaceDotProduct
353 const scalar orthWarn,
354 const polyMesh& mesh,
355 const vectorField& cellCentres,
356 const vectorField& faceAreas,
357 const labelList& checkFaces,
358 const List<labelPair>& baffles,
362 // for all internal and coupled faces check theat the d dot S product
365 const labelList& own = mesh.faceOwner();
366 const labelList& nei = mesh.faceNeighbour();
367 const polyBoundaryMesh& patches = mesh.boundaryMesh();
369 // Severe nonorthogonality threshold
370 const scalar severeNonorthogonalityThreshold =
371 ::cos(orthWarn/180.0*mathematicalConstant::pi);
374 // Calculate coupled cell centre
375 vectorField neiCc(mesh.nFaces()-mesh.nInternalFaces());
377 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
379 neiCc[faceI-mesh.nInternalFaces()] = cellCentres[own[faceI]];
381 syncTools::swapBoundaryFaceList(mesh, neiCc, true);
384 scalar minDDotS = GREAT;
389 label severeNonOrth = 0;
391 label errorNonOrth = 0;
393 forAll(checkFaces, i)
395 label faceI = checkFaces[i];
397 const point& ownCc = cellCentres[own[faceI]];
399 if (mesh.isInternalFace(faceI))
401 scalar dDotS = checkNonOrtho
405 severeNonorthogonalityThreshold,
408 cellCentres[nei[faceI]] - ownCc,
415 if (dDotS < minDDotS)
425 label patchI = patches.whichPatch(faceI);
427 if (patches[patchI].coupled())
429 scalar dDotS = checkNonOrtho
433 severeNonorthogonalityThreshold,
436 neiCc[faceI-mesh.nInternalFaces()] - ownCc,
443 if (dDotS < minDDotS)
456 label face0 = baffles[i].first();
457 label face1 = baffles[i].second();
459 const point& ownCc = cellCentres[own[face0]];
461 scalar dDotS = checkNonOrtho
465 severeNonorthogonalityThreshold,
468 cellCentres[own[face1]] - ownCc,
475 if (dDotS < minDDotS)
484 reduce(minDDotS, minOp<scalar>());
485 reduce(sumDDotS, sumOp<scalar>());
486 reduce(nDDotS, sumOp<label>());
487 reduce(severeNonOrth, sumOp<label>());
488 reduce(errorNonOrth, sumOp<label>());
490 // Only report if there are some internal faces
493 if (report && minDDotS < severeNonorthogonalityThreshold)
495 Info<< "Number of non-orthogonality errors: " << errorNonOrth
496 << ". Number of severely non-orthogonal faces: "
497 << severeNonOrth << "." << endl;
505 Info<< "Mesh non-orthogonality Max: "
506 << ::acos(minDDotS)/mathematicalConstant::pi*180.0
508 ::acos(sumDDotS/nDDotS)/mathematicalConstant::pi*180.0
513 if (errorNonOrth > 0)
519 "polyMeshGeometry::checkFaceDotProduct"
520 "(const bool, const scalar, const labelList&, labelHashSet*)"
521 ) << "Error in non-orthogonality detected" << endl;
530 Info<< "Non-orthogonality check OK.\n" << endl;
538 bool Foam::polyMeshGeometry::checkFacePyramids
541 const scalar minPyrVol,
542 const polyMesh& mesh,
543 const vectorField& cellCentres,
545 const labelList& checkFaces,
546 const List<labelPair>& baffles,
550 // check whether face area vector points to the cell with higher label
551 const labelList& own = mesh.faceOwner();
552 const labelList& nei = mesh.faceNeighbour();
554 const faceList& f = mesh.faces();
556 label nErrorPyrs = 0;
558 forAll(checkFaces, i)
560 label faceI = checkFaces[i];
562 // Create the owner pyramid - it will have negative volume
563 scalar pyrVol = pyramidPointFaceRef
566 cellCentres[own[faceI]]
569 if (pyrVol > -minPyrVol)
573 Pout<< "bool polyMeshGeometry::checkFacePyramids("
574 << "const bool, const scalar, const pointField&"
575 << ", const labelList&, labelHashSet*): "
576 << "face " << faceI << " points the wrong way. " << endl
577 << "Pyramid volume: " << -pyrVol
578 << " Face " << f[faceI] << " area: " << f[faceI].mag(p)
579 << " Owner cell: " << own[faceI] << endl
580 << "Owner cell vertex labels: "
581 << mesh.cells()[own[faceI]].labels(f)
588 setPtr->insert(faceI);
594 if (mesh.isInternalFace(faceI))
596 // Create the neighbour pyramid - it will have positive volume
598 pyramidPointFaceRef(f[faceI], cellCentres[nei[faceI]]).mag(p);
600 if (pyrVol < minPyrVol)
604 Pout<< "bool polyMeshGeometry::checkFacePyramids("
605 << "const bool, const scalar, const pointField&"
606 << ", const labelList&, labelHashSet*): "
607 << "face " << faceI << " points the wrong way. " << endl
608 << "Pyramid volume: " << -pyrVol
609 << " Face " << f[faceI] << " area: " << f[faceI].mag(p)
610 << " Neighbour cell: " << nei[faceI] << endl
611 << "Neighbour cell vertex labels: "
612 << mesh.cells()[nei[faceI]].labels(f)
618 setPtr->insert(faceI);
628 label face0 = baffles[i].first();
629 label face1 = baffles[i].second();
631 const point& ownCc = cellCentres[own[face0]];
633 // Create the owner pyramid - it will have negative volume
634 scalar pyrVolOwn = pyramidPointFaceRef
640 if (pyrVolOwn > -minPyrVol)
644 Pout<< "bool polyMeshGeometry::checkFacePyramids("
645 << "const bool, const scalar, const pointField&"
646 << ", const labelList&, labelHashSet*): "
647 << "face " << face0 << " points the wrong way. " << endl
648 << "Pyramid volume: " << -pyrVolOwn
649 << " Face " << f[face0] << " area: " << f[face0].mag(p)
650 << " Owner cell: " << own[face0] << endl
651 << "Owner cell vertex labels: "
652 << mesh.cells()[own[face0]].labels(f)
659 setPtr->insert(face0);
665 // Create the neighbour pyramid - it will have positive volume
667 pyramidPointFaceRef(f[face0], cellCentres[own[face1]]).mag(p);
669 if (pyrVolNbr < minPyrVol)
673 Pout<< "bool polyMeshGeometry::checkFacePyramids("
674 << "const bool, const scalar, const pointField&"
675 << ", const labelList&, labelHashSet*): "
676 << "face " << face0 << " points the wrong way. " << endl
677 << "Pyramid volume: " << -pyrVolNbr
678 << " Face " << f[face0] << " area: " << f[face0].mag(p)
679 << " Neighbour cell: " << own[face1] << endl
680 << "Neighbour cell vertex labels: "
681 << mesh.cells()[own[face1]].labels(f)
687 setPtr->insert(face0);
694 reduce(nErrorPyrs, sumOp<label>());
702 "polyMeshGeometry::checkFacePyramids("
703 "const bool, const scalar, const pointField&"
704 ", const labelList&, labelHashSet*)"
705 ) << "Error in face pyramids: faces pointing the wrong way!"
715 Info<< "Face pyramids OK.\n" << endl;
723 bool Foam::polyMeshGeometry::checkFaceSkewness
726 const scalar internalSkew,
727 const scalar boundarySkew,
728 const polyMesh& mesh,
729 const vectorField& cellCentres,
730 const vectorField& faceCentres,
731 const vectorField& faceAreas,
732 const labelList& checkFaces,
733 const List<labelPair>& baffles,
737 // Warn if the skew correction vector is more than skew times
738 // larger than the face area vector
740 const labelList& own = mesh.faceOwner();
741 const labelList& nei = mesh.faceNeighbour();
742 const polyBoundaryMesh& patches = mesh.boundaryMesh();
744 // Calculate coupled cell centre
745 vectorField neiCc(mesh.nFaces()-mesh.nInternalFaces());
747 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
749 neiCc[faceI-mesh.nInternalFaces()] = cellCentres[own[faceI]];
751 syncTools::swapBoundaryFaceList(mesh, neiCc, true);
758 forAll(checkFaces, i)
760 label faceI = checkFaces[i];
762 if (mesh.isInternalFace(faceI))
764 scalar skewness = calcSkewness
766 cellCentres[own[faceI]],
767 cellCentres[nei[faceI]],
771 // Check if the skewness vector is greater than the PN vector.
772 // This does not cause trouble but is a good indication of a poor
774 if (skewness > internalSkew)
778 Pout<< "Severe skewness for face " << faceI
779 << " skewness = " << skewness << endl;
784 setPtr->insert(faceI);
790 maxSkew = max(maxSkew, skewness);
792 else if (patches[patches.whichPatch(faceI)].coupled())
794 scalar skewness = calcSkewness
796 cellCentres[own[faceI]],
797 neiCc[faceI-mesh.nInternalFaces()],
801 // Check if the skewness vector is greater than the PN vector.
802 // This does not cause trouble but is a good indication of a poor
804 if (skewness > internalSkew)
808 Pout<< "Severe skewness for coupled face " << faceI
809 << " skewness = " << skewness << endl;
814 setPtr->insert(faceI);
820 maxSkew = max(maxSkew, skewness);
824 // Boundary faces: consider them to have only skewness error.
825 // (i.e. treat as if mirror cell on other side)
827 vector faceNormal = faceAreas[faceI];
828 faceNormal /= mag(faceNormal) + ROOTVSMALL;
830 vector dOwn = faceCentres[faceI] - cellCentres[own[faceI]];
832 vector dWall = faceNormal*(faceNormal & dOwn);
834 point faceIntersection = cellCentres[own[faceI]] + dWall;
837 mag(faceCentres[faceI] - faceIntersection)
838 /(2*mag(dWall) + ROOTVSMALL);
840 // Check if the skewness vector is greater than the PN vector.
841 // This does not cause trouble but is a good indication of a poor
843 if (skewness > boundarySkew)
847 Pout<< "Severe skewness for boundary face " << faceI
848 << " skewness = " << skewness << endl;
853 setPtr->insert(faceI);
859 maxSkew = max(maxSkew, skewness);
865 label face0 = baffles[i].first();
866 label face1 = baffles[i].second();
868 const point& ownCc = cellCentres[own[face0]];
870 scalar skewness = calcSkewness
873 cellCentres[own[face1]],
877 // Check if the skewness vector is greater than the PN vector.
878 // This does not cause trouble but is a good indication of a poor
880 if (skewness > internalSkew)
884 Pout<< "Severe skewness for face " << face0
885 << " skewness = " << skewness << endl;
890 setPtr->insert(face0);
896 maxSkew = max(maxSkew, skewness);
900 reduce(maxSkew, maxOp<scalar>());
901 reduce(nWarnSkew, sumOp<label>());
909 "polyMeshGeometry::checkFaceSkewness"
910 "(const bool, const scalar, const labelList&, labelHashSet*)"
911 ) << "Large face skewness detected. Max skewness = "
913 << " percent.\nThis may impair the quality of the result." << nl
914 << nWarnSkew << " highly skew faces detected."
924 Info<< "Max skewness = " << 100*maxSkew
925 << " percent. Face skewness OK.\n" << endl;
933 bool Foam::polyMeshGeometry::checkFaceWeights
936 const scalar warnWeight,
937 const polyMesh& mesh,
938 const vectorField& cellCentres,
939 const vectorField& faceCentres,
940 const vectorField& faceAreas,
941 const labelList& checkFaces,
942 const List<labelPair>& baffles,
946 // Warn if the delta factor (0..1) is too large.
948 const labelList& own = mesh.faceOwner();
949 const labelList& nei = mesh.faceNeighbour();
950 const polyBoundaryMesh& patches = mesh.boundaryMesh();
952 // Calculate coupled cell centre
953 vectorField neiCc(mesh.nFaces()-mesh.nInternalFaces());
955 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
957 neiCc[faceI-mesh.nInternalFaces()] = cellCentres[own[faceI]];
959 syncTools::swapBoundaryFaceList(mesh, neiCc, true);
962 scalar minWeight = GREAT;
964 label nWarnWeight = 0;
966 forAll(checkFaces, i)
968 label faceI = checkFaces[i];
970 const point& fc = faceCentres[faceI];
971 const vector& fa = faceAreas[faceI];
973 scalar dOwn = mag(fa & (fc-cellCentres[own[faceI]]));
975 if (mesh.isInternalFace(faceI))
977 scalar dNei = mag(fa & (cellCentres[nei[faceI]]-fc));
978 scalar weight = min(dNei,dOwn)/(dNei+dOwn+VSMALL);
980 if (weight < warnWeight)
984 Pout<< "Small weighting factor for face " << faceI
985 << " weight = " << weight << endl;
990 setPtr->insert(faceI);
996 minWeight = min(minWeight, weight);
1000 label patchI = patches.whichPatch(faceI);
1002 if (patches[patchI].coupled())
1004 scalar dNei = mag(fa & (neiCc[faceI-mesh.nInternalFaces()]-fc));
1005 scalar weight = min(dNei,dOwn)/(dNei+dOwn+VSMALL);
1007 if (weight < warnWeight)
1011 Pout<< "Small weighting factor for face " << faceI
1012 << " weight = " << weight << endl;
1017 setPtr->insert(faceI);
1023 minWeight = min(minWeight, weight);
1030 label face0 = baffles[i].first();
1031 label face1 = baffles[i].second();
1033 const point& ownCc = cellCentres[own[face0]];
1034 const point& fc = faceCentres[face0];
1035 const vector& fa = faceAreas[face0];
1037 scalar dOwn = mag(fa & (fc-ownCc));
1038 scalar dNei = mag(fa & (cellCentres[own[face1]]-fc));
1039 scalar weight = min(dNei,dOwn)/(dNei+dOwn+VSMALL);
1041 if (weight < warnWeight)
1045 Pout<< "Small weighting factor for face " << face0
1046 << " weight = " << weight << endl;
1051 setPtr->insert(face0);
1057 minWeight = min(minWeight, weight);
1060 reduce(minWeight, minOp<scalar>());
1061 reduce(nWarnWeight, sumOp<label>());
1063 if (minWeight < warnWeight)
1069 "polyMeshGeometry::checkFaceWeights"
1070 "(const bool, const scalar, const labelList&, labelHashSet*)"
1071 ) << "Small interpolation weight detected. Min weight = "
1072 << minWeight << '.' << nl
1073 << nWarnWeight << " faces with small weights detected."
1083 Info<< "Min weight = " << minWeight
1084 << ". Weights OK.\n" << endl;
1092 bool Foam::polyMeshGeometry::checkVolRatio
1095 const scalar warnRatio,
1096 const polyMesh& mesh,
1097 const scalarField& cellVolumes,
1098 const labelList& checkFaces,
1099 const List<labelPair>& baffles,
1100 labelHashSet* setPtr
1103 // Warn if the volume ratio between neighbouring cells is too large
1105 const labelList& own = mesh.faceOwner();
1106 const labelList& nei = mesh.faceNeighbour();
1107 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1109 // Calculate coupled cell vol
1110 scalarField neiVols(mesh.nFaces()-mesh.nInternalFaces());
1112 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
1114 neiVols[faceI-mesh.nInternalFaces()] = cellVolumes[own[faceI]];
1116 syncTools::swapBoundaryFaceList(mesh, neiVols, true);
1119 scalar minRatio = GREAT;
1121 label nWarnRatio = 0;
1123 forAll(checkFaces, i)
1125 label faceI = checkFaces[i];
1127 scalar ownVol = mag(cellVolumes[own[faceI]]);
1129 scalar neiVol = -GREAT;
1131 if (mesh.isInternalFace(faceI))
1133 neiVol = mag(cellVolumes[nei[faceI]]);
1137 label patchI = patches.whichPatch(faceI);
1139 if (patches[patchI].coupled())
1141 neiVol = mag(neiVols[faceI-mesh.nInternalFaces()]);
1147 scalar ratio = min(ownVol, neiVol) / (max(ownVol, neiVol) + VSMALL);
1149 if (ratio < warnRatio)
1153 Pout<< "Small ratio for face " << faceI
1154 << " ratio = " << ratio << endl;
1159 setPtr->insert(faceI);
1165 minRatio = min(minRatio, ratio);
1171 label face0 = baffles[i].first();
1172 label face1 = baffles[i].second();
1174 scalar ownVol = mag(cellVolumes[own[face0]]);
1176 scalar neiVol = mag(cellVolumes[own[face1]]);
1180 scalar ratio = min(ownVol, neiVol) / (max(ownVol, neiVol) + VSMALL);
1182 if (ratio < warnRatio)
1186 Pout<< "Small ratio for face " << face0
1187 << " ratio = " << ratio << endl;
1192 setPtr->insert(face0);
1198 minRatio = min(minRatio, ratio);
1202 reduce(minRatio, minOp<scalar>());
1203 reduce(nWarnRatio, sumOp<label>());
1205 if (minRatio < warnRatio)
1211 "polyMeshGeometry::checkVolRatio"
1212 "(const bool, const scalar, const labelList&, labelHashSet*)"
1213 ) << "Small volume ratio detected. Min ratio = "
1214 << minRatio << '.' << nl
1215 << nWarnRatio << " faces with small ratios detected."
1225 Info<< "Min ratio = " << minRatio
1226 << ". Ratios OK.\n" << endl;
1234 // Check convexity of angles in a face. Allow a slight non-convexity.
1235 // E.g. maxDeg = 10 allows for angles < 190 (or 10 degrees concavity)
1236 // (if truly concave and points not visible from face centre the face-pyramid
1237 // check in checkMesh will fail)
1238 bool Foam::polyMeshGeometry::checkFaceAngles
1241 const scalar maxDeg,
1242 const polyMesh& mesh,
1243 const vectorField& faceAreas,
1244 const pointField& p,
1245 const labelList& checkFaces,
1246 labelHashSet* setPtr
1249 if (maxDeg < -SMALL || maxDeg > 180+SMALL)
1253 "polyMeshGeometry::checkFaceAngles"
1254 "(const bool, const scalar, const pointField&, const labelList&"
1256 ) << "maxDeg should be [0..180] but is now " << maxDeg
1257 << abort(FatalError);
1260 const scalar maxSin = Foam::sin(maxDeg/180.0*mathematicalConstant::pi);
1262 const faceList& fcs = mesh.faces();
1264 scalar maxEdgeSin = 0.0;
1268 label errorFaceI = -1;
1270 forAll(checkFaces, i)
1272 label faceI = checkFaces[i];
1274 const face& f = fcs[faceI];
1276 vector faceNormal = faceAreas[faceI];
1277 faceNormal /= mag(faceNormal) + VSMALL;
1279 // Get edge from f[0] to f[size-1];
1280 vector ePrev(p[f[0]] - p[f[f.size()-1]]);
1281 scalar magEPrev = mag(ePrev);
1282 ePrev /= magEPrev + VSMALL;
1286 // Get vertex after fp
1287 label fp1 = f.fcIndex(fp0);
1289 // Normalized vector between two consecutive points
1290 vector e10(p[f[fp1]] - p[f[fp0]]);
1291 scalar magE10 = mag(e10);
1292 e10 /= magE10 + VSMALL;
1294 if (magEPrev > SMALL && magE10 > SMALL)
1296 vector edgeNormal = ePrev ^ e10;
1297 scalar magEdgeNormal = mag(edgeNormal);
1299 if (magEdgeNormal < maxSin)
1301 // Edges (almost) aligned -> face is ok.
1306 edgeNormal /= magEdgeNormal;
1308 if ((edgeNormal & faceNormal) < SMALL)
1310 if (faceI != errorFaceI)
1312 // Count only one error per face.
1319 setPtr->insert(faceI);
1322 maxEdgeSin = max(maxEdgeSin, magEdgeNormal);
1332 reduce(nConcave, sumOp<label>());
1333 reduce(maxEdgeSin, maxOp<scalar>());
1337 if (maxEdgeSin > SMALL)
1339 scalar maxConcaveDegr =
1340 Foam::asin(Foam::min(1.0, maxEdgeSin))
1341 * 180.0/mathematicalConstant::pi;
1343 Info<< "There are " << nConcave
1344 << " faces with concave angles between consecutive"
1345 << " edges. Max concave angle = " << maxConcaveDegr
1346 << " degrees.\n" << endl;
1350 Info<< "All angles in faces are convex or less than " << maxDeg
1351 << " degrees concave.\n" << endl;
1361 "polyMeshGeometry::checkFaceAngles"
1362 "(const bool, const scalar, const pointField&"
1363 ", const labelList&, labelHashSet*)"
1364 ) << nConcave << " face points with severe concave angle (> "
1365 << maxDeg << " deg) found.\n"
1378 // Check twist of faces. Is calculated as the difference between normals of
1379 // individual triangles and the cell-cell centre edge.
1380 bool Foam::polyMeshGeometry::checkFaceTwist
1383 const scalar minTwist,
1384 const polyMesh& mesh,
1385 const vectorField& cellCentres,
1386 const vectorField& faceAreas,
1387 const vectorField& faceCentres,
1388 const pointField& p,
1389 const labelList& checkFaces,
1390 labelHashSet* setPtr
1393 if (minTwist < -1-SMALL || minTwist > 1+SMALL)
1397 "polyMeshGeometry::checkFaceTwist"
1398 "(const bool, const scalar, const polyMesh&, const pointField&"
1399 ", const pointField&, const pointField&, const pointField&"
1400 ", const labelList&, labelHashSet*)"
1401 ) << "minTwist should be [-1..1] but is now " << minTwist
1402 << abort(FatalError);
1406 const faceList& fcs = mesh.faces();
1411 // forAll(checkFaces, i)
1413 // label faceI = checkFaces[i];
1415 // const face& f = fcs[faceI];
1417 // scalar magArea = mag(faceAreas[faceI]);
1419 // if (f.size() > 3 && magArea > VSMALL)
1421 // const vector nf = faceAreas[faceI] / magArea;
1423 // const point& fc = faceCentres[faceI];
1432 // p[f.nextLabel(fpI)],
1437 // scalar magTri = mag(triArea);
1439 // if (magTri > VSMALL && ((nf & triArea/magTri) < minTwist))
1445 // setPtr->insert(faceI);
1455 const labelList& own = mesh.faceOwner();
1456 const labelList& nei = mesh.faceNeighbour();
1457 const polyBoundaryMesh& patches = mesh.boundaryMesh();
1459 // Calculate coupled cell centre
1460 vectorField neiCc(mesh.nFaces()-mesh.nInternalFaces());
1462 for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
1464 neiCc[faceI-mesh.nInternalFaces()] = cellCentres[own[faceI]];
1466 syncTools::swapBoundaryFaceList(mesh, neiCc, true);
1468 forAll(checkFaces, i)
1470 label faceI = checkFaces[i];
1472 const face& f = fcs[faceI];
1476 vector nf(vector::zero);
1478 if (mesh.isInternalFace(faceI))
1480 nf = cellCentres[nei[faceI]] - cellCentres[own[faceI]];
1481 nf /= mag(nf) + VSMALL;
1483 else if (patches[patches.whichPatch(faceI)].coupled())
1486 neiCc[faceI-mesh.nInternalFaces()]
1487 - cellCentres[own[faceI]];
1488 nf /= mag(nf) + VSMALL;
1492 nf = faceCentres[faceI] - cellCentres[own[faceI]];
1493 nf /= mag(nf) + VSMALL;
1496 if (nf != vector::zero)
1498 const point& fc = faceCentres[faceI];
1507 p[f.nextLabel(fpI)],
1512 scalar magTri = mag(triArea);
1514 if (magTri > VSMALL && ((nf & triArea/magTri) < minTwist))
1520 setPtr->insert(faceI);
1530 reduce(nWarped, sumOp<label>());
1536 Info<< "There are " << nWarped
1537 << " faces with cosine of the angle"
1538 << " between triangle normal and face normal less than "
1539 << minTwist << nl << endl;
1543 Info<< "All faces are flat in that the cosine of the angle"
1544 << " between triangle normal and face normal less than "
1545 << minTwist << nl << endl;
1555 "polyMeshGeometry::checkFaceTwist"
1556 "(const bool, const scalar, const polyMesh&, const pointField&"
1557 ", const pointField&, const pointField&, const pointField&"
1558 ", const labelList&, labelHashSet*)"
1559 ) << nWarped << " faces with severe warpage "
1560 << "(cosine of the angle between triangle normal and face normal"
1561 << " < " << minTwist << ") found.\n"
1574 // Like checkFaceTwist but compares normals of consecutive triangles.
1575 bool Foam::polyMeshGeometry::checkTriangleTwist
1578 const scalar minTwist,
1579 const polyMesh& mesh,
1580 const vectorField& faceAreas,
1581 const vectorField& faceCentres,
1582 const pointField& p,
1583 const labelList& checkFaces,
1584 labelHashSet* setPtr
1587 if (minTwist < -1-SMALL || minTwist > 1+SMALL)
1591 "polyMeshGeometry::checkTriangleTwist"
1592 "(const bool, const scalar, const polyMesh&, const pointField&"
1593 ", const labelList&, labelHashSet*)"
1594 ) << "minTwist should be [-1..1] but is now " << minTwist
1595 << abort(FatalError);
1598 const faceList& fcs = mesh.faces();
1602 forAll(checkFaces, i)
1604 label faceI = checkFaces[i];
1606 const face& f = fcs[faceI];
1610 const point& fc = faceCentres[faceI];
1612 // Find starting triangle (at startFp) with non-zero area
1625 scalar magTri = mag(prevN);
1627 if (magTri > VSMALL)
1652 scalar magTri = mag(triN);
1654 if (magTri > VSMALL)
1658 if ((prevN & triN) < minTwist)
1664 setPtr->insert(faceI);
1672 else if (minTwist > 0)
1678 setPtr->insert(faceI);
1684 while (fp != startFp);
1690 reduce(nWarped, sumOp<label>());
1696 Info<< "There are " << nWarped
1697 << " faces with cosine of the angle"
1698 << " between consecutive triangle normals less than "
1699 << minTwist << nl << endl;
1703 Info<< "All faces are flat in that the cosine of the angle"
1704 << " between consecutive triangle normals is less than "
1705 << minTwist << nl << endl;
1715 "polyMeshGeometry::checkTriangleTwist"
1716 "(const bool, const scalar, const polyMesh&"
1717 ", const pointField&, const labelList&, labelHashSet*)"
1718 ) << nWarped << " faces with severe warpage "
1719 << "(cosine of the angle between consecutive triangle normals"
1720 << " < " << minTwist << ") found.\n"
1733 bool Foam::polyMeshGeometry::checkFaceArea
1736 const scalar minArea,
1737 const polyMesh& mesh,
1738 const vectorField& faceAreas,
1739 const labelList& checkFaces,
1740 labelHashSet* setPtr
1743 label nZeroArea = 0;
1745 forAll(checkFaces, i)
1747 label faceI = checkFaces[i];
1749 if (mag(faceAreas[faceI]) < minArea)
1753 setPtr->insert(faceI);
1760 reduce(nZeroArea, sumOp<label>());
1766 Info<< "There are " << nZeroArea
1767 << " faces with area < " << minArea << '.' << nl << endl;
1771 Info<< "All faces have area > " << minArea << '.' << nl << endl;
1781 "polyMeshGeometry::checkFaceArea"
1782 "(const bool, const scalar, const polyMesh&"
1783 ", const pointField&, const labelList&, labelHashSet*)"
1784 ) << nZeroArea << " faces with area < " << minArea
1798 bool Foam::polyMeshGeometry::checkCellDeterminant
1801 const scalar warnDet,
1802 const polyMesh& mesh,
1803 const vectorField& faceAreas,
1804 const labelList& checkFaces,
1805 const labelList& affectedCells,
1806 labelHashSet* setPtr
1809 const cellList& cells = mesh.cells();
1811 scalar minDet = GREAT;
1812 scalar sumDet = 0.0;
1816 forAll(affectedCells, i)
1818 const cell& cFaces = cells[affectedCells[i]];
1820 tensor areaSum(tensor::zero);
1821 scalar magAreaSum = 0;
1823 forAll(cFaces, cFaceI)
1825 label faceI = cFaces[cFaceI];
1827 scalar magArea = mag(faceAreas[faceI]);
1829 magAreaSum += magArea;
1830 areaSum += faceAreas[faceI]*(faceAreas[faceI]/(magArea+VSMALL));
1833 scalar scaledDet = det(areaSum/(magAreaSum+VSMALL))/0.037037037037037;
1835 minDet = min(minDet, scaledDet);
1836 sumDet += scaledDet;
1839 if (scaledDet < warnDet)
1843 // Insert all faces of the cell.
1844 forAll(cFaces, cFaceI)
1846 label faceI = cFaces[cFaceI];
1847 setPtr->insert(faceI);
1854 reduce(minDet, minOp<scalar>());
1855 reduce(sumDet, sumOp<scalar>());
1856 reduce(nSumDet, sumOp<label>());
1857 reduce(nWarnDet, sumOp<label>());
1863 Info<< "Cell determinant (1 = uniform cube) : average = "
1864 << sumDet / nSumDet << " min = " << minDet << endl;
1869 Info<< "There are " << nWarnDet
1870 << " cells with determinant < " << warnDet << '.' << nl
1875 Info<< "All faces have determinant > " << warnDet << '.' << nl
1886 "polyMeshGeometry::checkCellDeterminant"
1887 "(const bool, const scalar, const polyMesh&"
1888 ", const pointField&, const labelList&, const labelList&"
1890 ) << nWarnDet << " cells with determinant < " << warnDet
1904 bool Foam::polyMeshGeometry::checkFaceDotProduct
1907 const scalar orthWarn,
1908 const labelList& checkFaces,
1909 const List<labelPair>& baffles,
1910 labelHashSet* setPtr
1913 return checkFaceDotProduct
1927 bool Foam::polyMeshGeometry::checkFacePyramids
1930 const scalar minPyrVol,
1931 const pointField& p,
1932 const labelList& checkFaces,
1933 const List<labelPair>& baffles,
1934 labelHashSet* setPtr
1937 return checkFacePyramids
1951 bool Foam::polyMeshGeometry::checkFaceSkewness
1954 const scalar internalSkew,
1955 const scalar boundarySkew,
1956 const labelList& checkFaces,
1957 const List<labelPair>& baffles,
1958 labelHashSet* setPtr
1961 return checkFaceSkewness
1977 bool Foam::polyMeshGeometry::checkFaceWeights
1980 const scalar warnWeight,
1981 const labelList& checkFaces,
1982 const List<labelPair>& baffles,
1983 labelHashSet* setPtr
1986 return checkFaceWeights
2001 bool Foam::polyMeshGeometry::checkVolRatio
2004 const scalar warnRatio,
2005 const labelList& checkFaces,
2006 const List<labelPair>& baffles,
2007 labelHashSet* setPtr
2010 return checkVolRatio
2023 bool Foam::polyMeshGeometry::checkFaceAngles
2026 const scalar maxDeg,
2027 const pointField& p,
2028 const labelList& checkFaces,
2029 labelHashSet* setPtr
2032 return checkFaceAngles
2045 bool Foam::polyMeshGeometry::checkFaceTwist
2048 const scalar minTwist,
2049 const pointField& p,
2050 const labelList& checkFaces,
2051 labelHashSet* setPtr
2054 return checkFaceTwist
2069 bool Foam::polyMeshGeometry::checkTriangleTwist
2072 const scalar minTwist,
2073 const pointField& p,
2074 const labelList& checkFaces,
2075 labelHashSet* setPtr
2078 return checkTriangleTwist
2092 bool Foam::polyMeshGeometry::checkFaceArea
2095 const scalar minArea,
2096 const labelList& checkFaces,
2097 labelHashSet* setPtr
2100 return checkFaceArea
2112 bool Foam::polyMeshGeometry::checkCellDeterminant
2115 const scalar warnDet,
2116 const labelList& checkFaces,
2117 const labelList& affectedCells,
2118 labelHashSet* setPtr
2121 return checkCellDeterminant
2134 // ************************************************************************* //