00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <OpenFOAM/primitiveMesh.H>
00027 #include <OpenFOAM/pyramidPointFaceRef.H>
00028 #include <OpenFOAM/ListOps.H>
00029 #include <OpenFOAM/mathematicalConstants.H>
00030 #include <OpenFOAM/SortableList.H>
00031
00032
00033
00034
00035 Foam::scalar Foam::primitiveMesh::closedThreshold_ = 1.0e-6;
00036 Foam::scalar Foam::primitiveMesh::aspectThreshold_ = 1000;
00037 Foam::scalar Foam::primitiveMesh::nonOrthThreshold_ = 70;
00038 Foam::scalar Foam::primitiveMesh::skewThreshold_ = 4;
00039
00040
00041
00042
00043 bool Foam::primitiveMesh::checkClosedBoundary(const bool report) const
00044 {
00045 if (debug)
00046 {
00047 Info<< "bool primitiveMesh::checkClosedBoundary("
00048 << "const bool) const: "
00049 << "checking whether the boundary is closed" << endl;
00050 }
00051
00052
00053
00054
00055 vector sumClosed(vector::zero);
00056 scalar sumMagClosedBoundary = 0;
00057
00058 const vectorField& areas = faceAreas();
00059
00060 for (label faceI = nInternalFaces(); faceI < areas.size(); faceI++)
00061 {
00062 sumClosed += areas[faceI];
00063 sumMagClosedBoundary += mag(areas[faceI]);
00064 }
00065
00066 reduce(sumClosed, sumOp<vector>());
00067 reduce(sumMagClosedBoundary, sumOp<scalar>());
00068
00069 vector openness = sumClosed/(sumMagClosedBoundary + VSMALL);
00070
00071 if (cmptMax(cmptMag(openness)) > closedThreshold_)
00072 {
00073 if (debug || report)
00074 {
00075 Info<< " ***Boundary openness " << openness
00076 << " possible hole in boundary description."
00077 << endl;
00078 }
00079
00080 return true;
00081 }
00082 else
00083 {
00084 if (debug || report)
00085 {
00086 Info<< " Boundary openness " << openness << " OK."
00087 << endl;
00088 }
00089
00090 return false;
00091 }
00092 }
00093
00094
00095 bool Foam::primitiveMesh::checkClosedCells
00096 (
00097 const bool report,
00098 labelHashSet* setPtr,
00099 labelHashSet* aspectSetPtr,
00100 const Vector<label>& meshD
00101 ) const
00102 {
00103 if (debug)
00104 {
00105 Info<< "bool primitiveMesh::checkClosedCells("
00106 << "const bool, labelHashSet*, labelHashSet*"
00107 << ", const Vector<label>&) const: "
00108 << "checking whether cells are closed" << endl;
00109 }
00110
00111
00112 const cellList& c = cells();
00113
00114 label nErrorClosed = 0;
00115
00116 forAll (c, cI)
00117 {
00118 const cell& curCell = c[cI];
00119
00120 if (min(curCell) < 0 || max(curCell) > nFaces())
00121 {
00122 if (setPtr)
00123 {
00124 setPtr->insert(cI);
00125 }
00126
00127 nErrorClosed++;
00128 }
00129 }
00130
00131 if (nErrorClosed > 0)
00132 {
00133 if (debug || report)
00134 {
00135 Info<< " ***Cells with invalid face labels found, number of cells "
00136 << nErrorClosed << endl;
00137 }
00138
00139 return true;
00140 }
00141
00142
00143
00144
00145 vectorField sumClosed(nCells(), vector::zero);
00146 vectorField sumMagClosed(nCells(), vector::zero);
00147
00148 const labelList& own = faceOwner();
00149 const labelList& nei = faceNeighbour();
00150 const vectorField& areas = faceAreas();
00151
00152 forAll (own, faceI)
00153 {
00154
00155 sumClosed[own[faceI]] += areas[faceI];
00156 sumMagClosed[own[faceI]] += cmptMag(areas[faceI]);
00157 }
00158
00159 forAll (nei, faceI)
00160 {
00161
00162 sumClosed[nei[faceI]] -= areas[faceI];
00163 sumMagClosed[nei[faceI]] += cmptMag(areas[faceI]);
00164 }
00165
00166 label nOpen = 0;
00167 scalar maxOpennessCell = 0;
00168
00169 label nAspect = 0;
00170 scalar maxAspectRatio = 0;
00171
00172 const scalarField& vols = cellVolumes();
00173
00174 label nDims = 0;
00175 for (direction dir = 0; dir < vector::nComponents; dir++)
00176 {
00177 if (meshD[dir] == 1)
00178 {
00179 nDims++;
00180 }
00181 }
00182
00183
00184
00185 forAll(sumClosed, cellI)
00186 {
00187 scalar maxOpenness = 0;
00188
00189 for(direction cmpt=0; cmpt<vector::nComponents; cmpt++)
00190 {
00191 maxOpenness = max
00192 (
00193 maxOpenness,
00194 mag(sumClosed[cellI][cmpt])
00195 /(sumMagClosed[cellI][cmpt] + VSMALL)
00196 );
00197 }
00198
00199 maxOpennessCell = max(maxOpennessCell, maxOpenness);
00200
00201 if (maxOpenness > closedThreshold_)
00202 {
00203 if (setPtr)
00204 {
00205 setPtr->insert(cellI);
00206 }
00207
00208 nOpen++;
00209 }
00210
00211
00212
00213 scalar minCmpt = VGREAT;
00214 scalar maxCmpt = -VGREAT;
00215 for (direction dir = 0; dir < vector::nComponents; dir++)
00216 {
00217 if (meshD[dir] == 1)
00218 {
00219 minCmpt = min(minCmpt, sumMagClosed[cellI][dir]);
00220 maxCmpt = max(maxCmpt, sumMagClosed[cellI][dir]);
00221 }
00222 }
00223
00224 scalar aspectRatio = maxCmpt/(minCmpt + VSMALL);
00225 if (nDims == 3)
00226 {
00227 aspectRatio = max
00228 (
00229 aspectRatio,
00230 1.0/6.0*cmptSum(sumMagClosed[cellI])/pow(vols[cellI], 2.0/3.0)
00231 );
00232 }
00233
00234 maxAspectRatio = max(maxAspectRatio, aspectRatio);
00235
00236 if (aspectRatio > aspectThreshold_)
00237 {
00238 if (aspectSetPtr)
00239 {
00240 aspectSetPtr->insert(cellI);
00241 }
00242
00243 nAspect++;
00244 }
00245 }
00246
00247 reduce(nOpen, sumOp<label>());
00248 reduce(maxOpennessCell, maxOp<scalar>());
00249
00250 reduce(nAspect, sumOp<label>());
00251 reduce(maxAspectRatio, maxOp<scalar>());
00252
00253
00254 if (nOpen > 0)
00255 {
00256 if (debug || report)
00257 {
00258 Info<< " ***Open cells found, max cell openness: "
00259 << maxOpennessCell << ", number of open cells " << nOpen
00260 << endl;
00261 }
00262
00263 return true;
00264 }
00265
00266 if (nAspect > 0)
00267 {
00268 if (debug || report)
00269 {
00270 Info<< " ***High aspect ratio cells found, Max aspect ratio: "
00271 << maxAspectRatio
00272 << ", number of cells " << nAspect
00273 << endl;
00274 }
00275
00276 return true;
00277 }
00278
00279 if (debug || report)
00280 {
00281 Info<< " Max cell openness = " << maxOpennessCell << " OK." << nl
00282 << " Max aspect ratio = " << maxAspectRatio << " OK."
00283 << endl;
00284 }
00285
00286 return false;
00287 }
00288
00289
00290 bool Foam::primitiveMesh::checkFaceAreas
00291 (
00292 const bool report,
00293 labelHashSet* setPtr
00294 ) const
00295 {
00296 if (debug)
00297 {
00298 Info<< "bool primitiveMesh::checkFaceAreas("
00299 << "const bool, labelHashSet*) const: "
00300 << "checking face area magnitudes" << endl;
00301 }
00302
00303 const scalarField magFaceAreas = mag(faceAreas());
00304
00305 scalar minArea = GREAT;
00306 scalar maxArea = -GREAT;
00307
00308 forAll (magFaceAreas, faceI)
00309 {
00310 if (magFaceAreas[faceI] < VSMALL)
00311 {
00312 if (setPtr)
00313 {
00314 setPtr->insert(faceI);
00315 }
00316 }
00317
00318 minArea = min(minArea, magFaceAreas[faceI]);
00319 maxArea = max(maxArea, magFaceAreas[faceI]);
00320 }
00321
00322 reduce(minArea, minOp<scalar>());
00323 reduce(maxArea, maxOp<scalar>());
00324
00325 if (minArea < VSMALL)
00326 {
00327 if (debug || report)
00328 {
00329 Info<< " ***Zero or negative face area detected. "
00330 "Minimum area: " << minArea << endl;
00331 }
00332
00333 return true;
00334 }
00335 else
00336 {
00337 if (debug || report)
00338 {
00339 Info<< " Minumum face area = " << minArea
00340 << ". Maximum face area = " << maxArea
00341 << ". Face area magnitudes OK." << endl;
00342 }
00343
00344 return false;
00345 }
00346 }
00347
00348
00349 bool Foam::primitiveMesh::checkCellVolumes
00350 (
00351 const bool report,
00352 labelHashSet* setPtr
00353 ) const
00354 {
00355 if (debug)
00356 {
00357 Info<< "bool primitiveMesh::checkCellVolumes("
00358 << "const bool, labelHashSet*) const: "
00359 << "checking cell volumes" << endl;
00360 }
00361
00362 const scalarField& vols = cellVolumes();
00363
00364 scalar minVolume = GREAT;
00365 scalar maxVolume = -GREAT;
00366
00367 label nNegVolCells = 0;
00368
00369 forAll (vols, cellI)
00370 {
00371 if (vols[cellI] < VSMALL)
00372 {
00373 if (setPtr)
00374 {
00375 setPtr->insert(cellI);
00376 }
00377
00378 nNegVolCells++;
00379 }
00380
00381 minVolume = min(minVolume, vols[cellI]);
00382 maxVolume = max(maxVolume, vols[cellI]);
00383 }
00384
00385 reduce(minVolume, minOp<scalar>());
00386 reduce(maxVolume, maxOp<scalar>());
00387 reduce(nNegVolCells, sumOp<label>());
00388
00389 if (minVolume < VSMALL)
00390 {
00391 if (debug || report)
00392 {
00393 Info<< " ***Zero or negative cell volume detected. "
00394 << "Minimum negative volume: " << minVolume
00395 << ", Number of negative volume cells: " << nNegVolCells
00396 << endl;
00397 }
00398
00399 return true;
00400 }
00401 else
00402 {
00403 if (debug || report)
00404 {
00405 Info<< " Min volume = " << minVolume
00406 << ". Max volume = " << maxVolume
00407 << ". Total volume = " << gSum(vols)
00408 << ". Cell volumes OK." << endl;
00409 }
00410
00411 return false;
00412 }
00413 }
00414
00415
00416 bool Foam::primitiveMesh::checkFaceOrthogonality
00417 (
00418 const bool report,
00419 labelHashSet* setPtr
00420 ) const
00421 {
00422 if (debug)
00423 {
00424 Info<< "bool primitiveMesh::checkFaceOrthogonality("
00425 << "const bool, labelHashSet*) const: "
00426 << "checking mesh non-orthogonality" << endl;
00427 }
00428
00429
00430 const vectorField& centres = cellCentres();
00431 const vectorField& areas = faceAreas();
00432
00433 const labelList& own = faceOwner();
00434 const labelList& nei = faceNeighbour();
00435
00436
00437 const scalar severeNonorthogonalityThreshold =
00438 ::cos(nonOrthThreshold_/180.0*mathematicalConstant::pi);
00439
00440 scalar minDDotS = GREAT;
00441
00442 scalar sumDDotS = 0;
00443
00444 label severeNonOrth = 0;
00445
00446 label errorNonOrth = 0;
00447
00448 forAll (nei, faceI)
00449 {
00450 vector d = centres[nei[faceI]] - centres[own[faceI]];
00451 const vector& s = areas[faceI];
00452
00453 scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
00454
00455 if (dDotS < severeNonorthogonalityThreshold)
00456 {
00457 if (dDotS > SMALL)
00458 {
00459 if (setPtr)
00460 {
00461 setPtr->insert(faceI);
00462 }
00463
00464 severeNonOrth++;
00465 }
00466 else
00467 {
00468 if (setPtr)
00469 {
00470 setPtr->insert(faceI);
00471 }
00472
00473 errorNonOrth++;
00474 }
00475 }
00476
00477 if (dDotS < minDDotS)
00478 {
00479 minDDotS = dDotS;
00480 }
00481
00482 sumDDotS += dDotS;
00483 }
00484
00485 reduce(minDDotS, minOp<scalar>());
00486 reduce(sumDDotS, sumOp<scalar>());
00487 reduce(severeNonOrth, sumOp<label>());
00488 reduce(errorNonOrth, sumOp<label>());
00489
00490 if (debug || report)
00491 {
00492 label neiSize = nei.size();
00493 reduce(neiSize, sumOp<label>());
00494
00495 if (neiSize > 0)
00496 {
00497 if (debug || report)
00498 {
00499 Info<< " Mesh non-orthogonality Max: "
00500 << ::acos(minDDotS)/mathematicalConstant::pi*180.0
00501 << " average: " <<
00502 ::acos(sumDDotS/neiSize)/mathematicalConstant::pi*180.0
00503 << endl;
00504 }
00505 }
00506
00507 if (severeNonOrth > 0)
00508 {
00509 Info<< " *Number of severely non-orthogonal faces: "
00510 << severeNonOrth << "." << endl;
00511 }
00512 }
00513
00514 if (errorNonOrth > 0)
00515 {
00516 if (debug || report)
00517 {
00518 Info<< " ***Number of non-orthogonality errors: "
00519 << errorNonOrth << "." << endl;
00520 }
00521
00522 return true;
00523 }
00524 else
00525 {
00526 if (debug || report)
00527 {
00528 Info<< " Non-orthogonality check OK." << endl;
00529 }
00530
00531 return false;
00532 }
00533 }
00534
00535
00536 bool Foam::primitiveMesh::checkFacePyramids
00537 (
00538 const bool report,
00539 const scalar minPyrVol,
00540 labelHashSet* setPtr
00541 ) const
00542 {
00543 if (debug)
00544 {
00545 Info<< "bool primitiveMesh::checkFacePyramids("
00546 << "const bool, const scalar, labelHashSet*) const: "
00547 << "checking face orientation" << endl;
00548 }
00549
00550
00551 const vectorField& ctrs = cellCentres();
00552
00553 const labelList& own = faceOwner();
00554 const labelList& nei = faceNeighbour();
00555
00556 const faceList& f = faces();
00557
00558 const pointField& p = points();
00559
00560 label nErrorPyrs = 0;
00561
00562 forAll (f, faceI)
00563 {
00564
00565 scalar pyrVol = pyramidPointFaceRef(f[faceI], ctrs[own[faceI]]).mag(p);
00566
00567 if (pyrVol > -minPyrVol)
00568 {
00569 if (setPtr)
00570 {
00571 setPtr->insert(faceI);
00572 }
00573
00574 nErrorPyrs++;
00575 }
00576
00577 if (isInternalFace(faceI))
00578 {
00579
00580 scalar pyrVol =
00581 pyramidPointFaceRef(f[faceI], ctrs[nei[faceI]]).mag(p);
00582
00583 if (pyrVol < minPyrVol)
00584 {
00585 if (setPtr)
00586 {
00587 setPtr->insert(faceI);
00588 }
00589
00590 nErrorPyrs++;
00591 }
00592 }
00593 }
00594
00595 reduce(nErrorPyrs, sumOp<label>());
00596
00597 if (nErrorPyrs > 0)
00598 {
00599 if (debug || report)
00600 {
00601 Info<< " ***Error in face pyramids: "
00602 << nErrorPyrs << " faces are incorrectly oriented."
00603 << endl;
00604 }
00605
00606 return true;
00607 }
00608 else
00609 {
00610 if (debug || report)
00611 {
00612 Info<< " Face pyramids OK." << endl;
00613 }
00614
00615 return false;
00616 }
00617 }
00618
00619
00620 bool Foam::primitiveMesh::checkFaceSkewness
00621 (
00622 const bool report,
00623 labelHashSet* setPtr
00624 ) const
00625 {
00626 if (debug)
00627 {
00628 Info<< "bool primitiveMesh::checkFaceSkewnesss("
00629 << "const bool, labelHashSet*) const: "
00630 << "checking face skewness" << endl;
00631 }
00632
00633
00634
00635
00636 const pointField& p = points();
00637 const faceList& fcs = faces();
00638
00639 const labelList& own = faceOwner();
00640 const labelList& nei = faceNeighbour();
00641 const vectorField& cellCtrs = cellCentres();
00642 const vectorField& faceCtrs = faceCentres();
00643 const vectorField& fAreas = faceAreas();
00644
00645 scalar maxSkew = 0;
00646 label nWarnSkew = 0;
00647
00648 forAll(nei, faceI)
00649 {
00650 vector Cpf = faceCtrs[faceI] - cellCtrs[own[faceI]];
00651 vector d = cellCtrs[nei[faceI]] - cellCtrs[own[faceI]];
00652
00653
00654 vector sv =
00655 Cpf - ((fAreas[faceI] & Cpf)/((fAreas[faceI] & d) + SMALL))*d;
00656 vector svHat = sv/(mag(sv) + VSMALL);
00657
00658
00659
00660
00661 scalar fd = 0.2*mag(d) + VSMALL;
00662 const face& f = fcs[faceI];
00663 forAll(f, pi)
00664 {
00665 fd = max(fd, mag(svHat & (p[f[pi]] - faceCtrs[faceI])));
00666 }
00667
00668
00669 scalar skewness = mag(sv)/fd;
00670
00671
00672
00673 if (skewness > skewThreshold_)
00674 {
00675 if (setPtr)
00676 {
00677 setPtr->insert(faceI);
00678 }
00679
00680 nWarnSkew++;
00681 }
00682
00683 if(skewness > maxSkew)
00684 {
00685 maxSkew = skewness;
00686 }
00687 }
00688
00689
00690
00691
00692
00693 for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
00694 {
00695 vector Cpf = faceCtrs[faceI] - cellCtrs[own[faceI]];
00696
00697 vector normal = fAreas[faceI];
00698 normal /= mag(normal) + VSMALL;
00699 vector d = normal*(normal & Cpf);
00700
00701
00702
00703 vector sv = Cpf - ((fAreas[faceI]&Cpf)/((fAreas[faceI]&d)+VSMALL))*d;
00704 vector svHat = sv/(mag(sv) + VSMALL);
00705
00706
00707
00708
00709 scalar fd = 0.4*mag(d) + VSMALL;
00710 const face& f = fcs[faceI];
00711 forAll(f, pi)
00712 {
00713 fd = max(fd, mag(svHat & (p[f[pi]] - faceCtrs[faceI])));
00714 }
00715
00716
00717 scalar skewness = mag(sv)/fd;
00718
00719
00720
00721 if (skewness > skewThreshold_)
00722 {
00723 if (setPtr)
00724 {
00725 setPtr->insert(faceI);
00726 }
00727
00728 nWarnSkew++;
00729 }
00730
00731 if(skewness > maxSkew)
00732 {
00733 maxSkew = skewness;
00734 }
00735 }
00736
00737
00738 reduce(maxSkew, maxOp<scalar>());
00739 reduce(nWarnSkew, sumOp<label>());
00740
00741 if (nWarnSkew > 0)
00742 {
00743 if (debug || report)
00744 {
00745 Info<< " ***Max skewness = " << maxSkew
00746 << ", " << nWarnSkew << " highly skew faces detected"
00747 " which may impair the quality of the results"
00748 << endl;
00749 }
00750
00751 return true;
00752 }
00753 else
00754 {
00755 if (debug || report)
00756 {
00757 Info<< " Max skewness = " << maxSkew << " OK." << endl;
00758 }
00759
00760 return false;
00761 }
00762 }
00763
00764
00765 bool Foam::primitiveMesh::checkPoints
00766 (
00767 const bool report,
00768 labelHashSet* setPtr
00769 ) const
00770 {
00771 if (debug)
00772 {
00773 Info<< "bool primitiveMesh::checkPoints"
00774 << "(const bool, labelHashSet*) const: "
00775 << "checking points" << endl;
00776 }
00777
00778 label nFaceErrors = 0;
00779 label nCellErrors = 0;
00780
00781 const labelListList& pf = pointFaces();
00782
00783 forAll (pf, pointI)
00784 {
00785 if (pf[pointI].empty())
00786 {
00787 if (setPtr)
00788 {
00789 setPtr->insert(pointI);
00790 }
00791
00792 nFaceErrors++;
00793 }
00794 }
00795
00796
00797 forAll (pf, pointI)
00798 {
00799 const labelList& pc = pointCells(pointI);
00800
00801 if (pc.empty())
00802 {
00803 if (setPtr)
00804 {
00805 setPtr->insert(pointI);
00806 }
00807
00808 nCellErrors++;
00809 }
00810 }
00811
00812 reduce(nFaceErrors, sumOp<label>());
00813 reduce(nCellErrors, sumOp<label>());
00814
00815 if (nFaceErrors > 0 || nCellErrors > 0)
00816 {
00817 if (debug || report)
00818 {
00819 Info<< " ***Unused points found in the mesh, "
00820 "number unused by faces: " << nFaceErrors
00821 << " number unused by cells: " << nCellErrors
00822 << endl;
00823 }
00824
00825 return true;
00826 }
00827 else
00828 {
00829 if (debug || report)
00830 {
00831 Info<< " Point usage OK." << endl;
00832 }
00833
00834 return false;
00835 }
00836 }
00837
00838
00839
00840
00841
00842
00843 bool Foam::primitiveMesh::checkFaceAngles
00844 (
00845 const bool report,
00846 const scalar maxDeg,
00847 labelHashSet* setPtr
00848 ) const
00849 {
00850 if (debug)
00851 {
00852 Info<< "bool primitiveMesh::checkFaceAngles"
00853 << "(const bool, const scalar, labelHashSet*) const: "
00854 << "checking face angles" << endl;
00855 }
00856
00857 if (maxDeg < -SMALL || maxDeg > 180+SMALL)
00858 {
00859 FatalErrorIn
00860 (
00861 "primitiveMesh::checkFaceAngles"
00862 "(const bool, const scalar, labelHashSet*)"
00863 ) << "maxDeg should be [0..180] but is now " << maxDeg
00864 << exit(FatalError);
00865 }
00866
00867 const scalar maxSin = Foam::sin(maxDeg/180.0*mathematicalConstant::pi);
00868
00869 const pointField& p = points();
00870 const faceList& fcs = faces();
00871 vectorField faceNormals(faceAreas());
00872 faceNormals /= mag(faceNormals) + VSMALL;
00873
00874 scalar maxEdgeSin = 0.0;
00875
00876 label nConcave = 0;
00877
00878 label errorFaceI = -1;
00879
00880 forAll(fcs, faceI)
00881 {
00882 const face& f = fcs[faceI];
00883
00884
00885 vector ePrev(p[f[0]] - p[f[f.size()-1]]);
00886 scalar magEPrev = mag(ePrev);
00887 ePrev /= magEPrev + VSMALL;
00888
00889 forAll(f, fp0)
00890 {
00891
00892 label fp1 = f.fcIndex(fp0);
00893
00894
00895 vector e10(p[f[fp1]] - p[f[fp0]]);
00896 scalar magE10 = mag(e10);
00897 e10 /= magE10 + VSMALL;
00898
00899 if (magEPrev > SMALL && magE10 > SMALL)
00900 {
00901 vector edgeNormal = ePrev ^ e10;
00902 scalar magEdgeNormal = mag(edgeNormal);
00903
00904 if (magEdgeNormal < maxSin)
00905 {
00906
00907 }
00908 else
00909 {
00910
00911 edgeNormal /= magEdgeNormal;
00912
00913 if ((edgeNormal & faceNormals[faceI]) < SMALL)
00914 {
00915 if (faceI != errorFaceI)
00916 {
00917
00918 errorFaceI = faceI;
00919 nConcave++;
00920 }
00921
00922 if (setPtr)
00923 {
00924 setPtr->insert(faceI);
00925 }
00926
00927 maxEdgeSin = max(maxEdgeSin, magEdgeNormal);
00928 }
00929 }
00930 }
00931
00932 ePrev = e10;
00933 magEPrev = magE10;
00934 }
00935 }
00936
00937 reduce(nConcave, sumOp<label>());
00938 reduce(maxEdgeSin, maxOp<scalar>());
00939
00940 if (nConcave > 0)
00941 {
00942 scalar maxConcaveDegr =
00943 Foam::asin(Foam::min(1.0, maxEdgeSin))
00944 *180.0/mathematicalConstant::pi;
00945
00946 if (debug || report)
00947 {
00948 Info<< " *There are " << nConcave
00949 << " faces with concave angles between consecutive"
00950 << " edges. Max concave angle = " << maxConcaveDegr
00951 << " degrees." << endl;
00952 }
00953
00954 return true;
00955 }
00956 else
00957 {
00958 if (debug || report)
00959 {
00960 Info<< " All angles in faces OK." << endl;
00961 }
00962
00963 return false;
00964 }
00965 }
00966
00967
00968
00969
00970
00971 bool Foam::primitiveMesh::checkFaceFlatness
00972 (
00973 const bool report,
00974 const scalar warnFlatness,
00975 labelHashSet* setPtr
00976 ) const
00977 {
00978 if (debug)
00979 {
00980 Info<< "bool primitiveMesh::checkFaceFlatness"
00981 << "(const bool, const scalar, labelHashSet*) const: "
00982 << "checking face flatness" << endl;
00983 }
00984
00985 if (warnFlatness < 0 || warnFlatness > 1)
00986 {
00987 FatalErrorIn
00988 (
00989 "primitiveMesh::checkFaceFlatness"
00990 "(const bool, const scalar, labelHashSet*)"
00991 ) << "warnFlatness should be [0..1] but is now " << warnFlatness
00992 << exit(FatalError);
00993 }
00994
00995
00996 const pointField& p = points();
00997 const faceList& fcs = faces();
00998 const pointField& fctrs = faceCentres();
00999
01000
01001
01002 scalarField magAreas(mag(faceAreas()));
01003
01004 label nWarped = 0;
01005
01006 scalar minFlatness = GREAT;
01007 scalar sumFlatness = 0;
01008 label nSummed = 0;
01009
01010 forAll(fcs, faceI)
01011 {
01012 const face& f = fcs[faceI];
01013
01014 if (f.size() > 3 && magAreas[faceI] > VSMALL)
01015 {
01016 const point& fc = fctrs[faceI];
01017
01018
01019
01020
01021 scalar sumA = 0.0;
01022
01023 forAll(f, fp)
01024 {
01025 const point& thisPoint = p[f[fp]];
01026 const point& nextPoint = p[f.nextLabel(fp)];
01027
01028
01029 vector n = 0.5*((nextPoint - thisPoint)^(fc - thisPoint));
01030 sumA += mag(n);
01031 }
01032
01033 scalar flatness = magAreas[faceI] / (sumA+VSMALL);
01034
01035 sumFlatness += flatness;
01036 nSummed++;
01037
01038 minFlatness = min(minFlatness, flatness);
01039
01040 if (flatness < warnFlatness)
01041 {
01042 nWarped++;
01043
01044 if (setPtr)
01045 {
01046 setPtr->insert(faceI);
01047 }
01048 }
01049 }
01050 }
01051
01052
01053 reduce(nWarped, sumOp<label>());
01054 reduce(minFlatness, minOp<scalar>());
01055
01056 reduce(nSummed, sumOp<label>());
01057 reduce(sumFlatness, sumOp<scalar>());
01058
01059 if (debug || report)
01060 {
01061 if (nSummed > 0)
01062 {
01063 Info<< " Face flatness (1 = flat, 0 = butterfly) : average = "
01064 << sumFlatness / nSummed << " min = " << minFlatness << endl;
01065 }
01066 }
01067
01068
01069 if (nWarped> 0)
01070 {
01071 if (debug || report)
01072 {
01073 Info<< " *There are " << nWarped
01074 << " faces with ratio between projected and actual area < "
01075 << warnFlatness << endl;
01076
01077 Info<< " Minimum ratio (minimum flatness, maximum warpage) = "
01078 << minFlatness << endl;
01079 }
01080
01081 return true;
01082 }
01083 else
01084 {
01085 if (debug || report)
01086 {
01087 Info<< " All face flatness OK." << endl;
01088 }
01089
01090 return false;
01091 }
01092 }
01093
01094
01095
01096
01097
01098
01099
01100
01101 bool Foam::primitiveMesh::checkEdgeAlignment
01102 (
01103 const bool report,
01104 const Vector<label>& directions,
01105 labelHashSet* setPtr
01106 ) const
01107 {
01108 if (debug)
01109 {
01110 Info<< "bool primitiveMesh::checkEdgeAlignment("
01111 << "const bool, const Vector<label>&, labelHashSet*) const: "
01112 << "checking edge alignment" << endl;
01113 }
01114
01115 label nDirs = 0;
01116 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
01117 {
01118 if (directions[cmpt] == 1)
01119 {
01120 nDirs++;
01121 }
01122 else if (directions[cmpt] != 0)
01123 {
01124 FatalErrorIn
01125 (
01126 "primitiveMesh::checkEdgeAlignment"
01127 "(const bool, const Vector<label>&, labelHashSet*)"
01128 ) << "directions should contain 0 or 1 but is now " << directions
01129 << exit(FatalError);
01130 }
01131 }
01132
01133 if (nDirs == vector::nComponents)
01134 {
01135 return false;
01136 }
01137
01138
01139
01140 const pointField& p = points();
01141 const faceList& fcs = faces();
01142
01143 EdgeMap<label> edgesInError;
01144
01145 forAll(fcs, faceI)
01146 {
01147 const face& f = fcs[faceI];
01148
01149 forAll(f, fp)
01150 {
01151 label p0 = f[fp];
01152 label p1 = f.nextLabel(fp);
01153 if (p0 < p1)
01154 {
01155 vector d(p[p1]-p[p0]);
01156 scalar magD = mag(d);
01157
01158 if (magD > ROOTVSMALL)
01159 {
01160 d /= magD;
01161
01162
01163 label nEmptyDirs = 0;
01164 label nNonEmptyDirs = 0;
01165 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
01166 {
01167 if (mag(d[cmpt]) > 1e-6)
01168 {
01169 if (directions[cmpt] == 0)
01170 {
01171 nEmptyDirs++;
01172 }
01173 else
01174 {
01175 nNonEmptyDirs++;
01176 }
01177 }
01178 }
01179
01180 if (nEmptyDirs == 0)
01181 {
01182
01183 }
01184 else if (nEmptyDirs == 1)
01185 {
01186
01187 if (nNonEmptyDirs > 0)
01188 {
01189 edgesInError.insert(edge(p0, p1), faceI);
01190 }
01191 }
01192 else if (nEmptyDirs > 1)
01193 {
01194
01195 edgesInError.insert(edge(p0, p1), faceI);
01196 }
01197 }
01198 }
01199 }
01200 }
01201
01202 label nErrorEdges = returnReduce(edgesInError.size(), sumOp<label>());
01203
01204 if (nErrorEdges > 0)
01205 {
01206 if (debug || report)
01207 {
01208 Info<< " ***Number of edges not aligned with or perpendicular to "
01209 << "non-empty directions: " << nErrorEdges << endl;
01210 }
01211
01212 if (setPtr)
01213 {
01214 setPtr->resize(2*edgesInError.size());
01215 forAllConstIter(EdgeMap<label>, edgesInError, iter)
01216 {
01217 setPtr->insert(iter.key()[0]);
01218 setPtr->insert(iter.key()[1]);
01219 }
01220 }
01221
01222 return true;
01223 }
01224 else
01225 {
01226 if (debug || report)
01227 {
01228 Info<< " All edges aligned with or perpendicular to "
01229 << "non-empty directions." << endl;
01230 }
01231 return false;
01232 }
01233 }
01234
01235
01236 bool Foam::primitiveMesh::checkUpperTriangular
01237 (
01238 const bool report,
01239 labelHashSet* setPtr
01240 ) const
01241 {
01242 if (debug)
01243 {
01244 Info<< "bool primitiveMesh::checkUpperTriangular("
01245 << "const bool, labelHashSet*) const: "
01246 << "checking face ordering" << endl;
01247 }
01248
01249
01250 const labelList& own = faceOwner();
01251 const labelList& nei = faceNeighbour();
01252
01253 const cellList& c = cells();
01254
01255 label internal = nInternalFaces();
01256
01257
01258 bool error = false;
01259
01260 label nMultipleCells = false;
01261
01262
01263
01264 for (label faceI = 0; faceI < internal; faceI++)
01265 {
01266 if (own[faceI] >= nei[faceI])
01267 {
01268 error = true;
01269
01270 if (setPtr)
01271 {
01272 setPtr->insert(faceI);
01273 }
01274 }
01275 }
01276
01277
01278
01279
01280
01281 forAll (c, cellI)
01282 {
01283 const labelList& curFaces = c[cellI];
01284
01285
01286 SortableList<label> nbr(curFaces.size());
01287
01288 forAll(curFaces, i)
01289 {
01290 label faceI = curFaces[i];
01291
01292 if (faceI >= nInternalFaces())
01293 {
01294
01295 nbr[i] = labelMax;
01296 }
01297 else
01298 {
01299 label nbrCellI = nei[faceI];
01300
01301 if (nbrCellI == cellI)
01302 {
01303 nbrCellI = own[faceI];
01304 }
01305
01306 if (cellI < nbrCellI)
01307 {
01308
01309 nbr[i] = nbrCellI;
01310 }
01311 else
01312 {
01313
01314 nbr[i] = labelMax;
01315 }
01316 }
01317 }
01318
01319 nbr.sort();
01320
01321
01322
01323
01324
01325
01326 label prevCell = nbr[0];
01327 label prevFace = curFaces[nbr.indices()[0]];
01328
01329 bool hasMultipleFaces = false;
01330
01331 for (label i = 1; i < nbr.size(); i++)
01332 {
01333 label thisCell = nbr[i];
01334 label thisFace = curFaces[nbr.indices()[i]];
01335
01336 if (thisCell == labelMax)
01337 {
01338 break;
01339 }
01340
01341 if (thisCell == prevCell)
01342 {
01343 hasMultipleFaces = true;
01344
01345 if (setPtr)
01346 {
01347 setPtr->insert(prevFace);
01348 setPtr->insert(thisFace);
01349 }
01350 }
01351 else if (thisFace < prevFace)
01352 {
01353 error = true;
01354
01355 if (setPtr)
01356 {
01357 setPtr->insert(thisFace);
01358 }
01359 }
01360
01361 prevCell = thisCell;
01362 prevFace = thisFace;
01363 }
01364
01365 if (hasMultipleFaces)
01366 {
01367 nMultipleCells++;
01368 }
01369 }
01370
01371 reduce(error, orOp<bool>());
01372 reduce(nMultipleCells, sumOp<label>());
01373
01374 if ((debug || report) && nMultipleCells > 0)
01375 {
01376 Info<< " <<Found " << nMultipleCells
01377 << " neighbouring cells with multiple inbetween faces." << endl;
01378 }
01379
01380 if (error)
01381 {
01382 if (debug || report)
01383 {
01384 Info<< " ***Faces not in upper triangular order." << endl;
01385 }
01386
01387 return true;
01388 }
01389 else
01390 {
01391 if (debug || report)
01392 {
01393 Info<< " Upper triangular ordering OK." << endl;
01394 }
01395
01396 return false;
01397 }
01398 }
01399
01400
01401 bool Foam::primitiveMesh::checkCellsZipUp
01402 (
01403 const bool report,
01404 labelHashSet* setPtr
01405 ) const
01406 {
01407 if (debug)
01408 {
01409 Info<< "bool primitiveMesh::checkCellsZipUp("
01410 << "const bool, labelHashSet*) const: "
01411 << "checking topological cell openness" << endl;
01412 }
01413
01414 label nOpenCells = 0;
01415
01416 const faceList& f = faces();
01417 const cellList& c = cells();
01418
01419 forAll (c, cellI)
01420 {
01421 const labelList& curFaces = c[cellI];
01422
01423 const edgeList cellEdges = c[cellI].edges(f);
01424
01425 labelList edgeUsage(cellEdges.size(), 0);
01426
01427 forAll (curFaces, faceI)
01428 {
01429 edgeList curFaceEdges = f[curFaces[faceI]].edges();
01430
01431 forAll (curFaceEdges, faceEdgeI)
01432 {
01433 const edge& curEdge = curFaceEdges[faceEdgeI];
01434
01435 forAll (cellEdges, cellEdgeI)
01436 {
01437 if (cellEdges[cellEdgeI] == curEdge)
01438 {
01439 edgeUsage[cellEdgeI]++;
01440 break;
01441 }
01442 }
01443 }
01444 }
01445
01446 edgeList singleEdges(cellEdges.size());
01447 label nSingleEdges = 0;
01448
01449 forAll (edgeUsage, edgeI)
01450 {
01451 if (edgeUsage[edgeI] == 1)
01452 {
01453 singleEdges[nSingleEdges] = cellEdges[edgeI];
01454 nSingleEdges++;
01455 }
01456 else if (edgeUsage[edgeI] != 2)
01457 {
01458 if (setPtr)
01459 {
01460 setPtr->insert(cellI);
01461 }
01462 }
01463 }
01464
01465 if (nSingleEdges > 0)
01466 {
01467 if (setPtr)
01468 {
01469 setPtr->insert(cellI);
01470 }
01471
01472 nOpenCells++;
01473 }
01474 }
01475
01476 reduce(nOpenCells, sumOp<label>());
01477
01478 if (nOpenCells > 0)
01479 {
01480 if (debug || report)
01481 {
01482 Info<< " ***Open cells found, number of cells: " << nOpenCells
01483 << ". This problem may be fixable using the zipUpMesh utility."
01484 << endl;
01485 }
01486
01487 return true;
01488 }
01489 else
01490 {
01491 if (debug || report)
01492 {
01493 Info<< " Topological cell zip-up check OK." << endl;
01494 }
01495
01496 return false;
01497 }
01498 }
01499
01500
01501
01502 bool Foam::primitiveMesh::checkFaceVertices
01503 (
01504 const bool report,
01505 labelHashSet* setPtr
01506 ) const
01507 {
01508 if (debug)
01509 {
01510 Info<< "bool primitiveMesh::checkFaceVertices("
01511 << "const bool, labelHashSet*) const: "
01512 << "checking face vertices" << endl;
01513 }
01514
01515
01516 const faceList& f = faces();
01517
01518 label nErrorFaces = 0;
01519
01520 forAll (f, fI)
01521 {
01522 const face& curFace = f[fI];
01523
01524 if (min(curFace) < 0 || max(curFace) > nPoints())
01525 {
01526 if (setPtr)
01527 {
01528 setPtr->insert(fI);
01529 }
01530
01531 nErrorFaces++;
01532 }
01533
01534
01535 labelHashSet facePoints(2*curFace.size());
01536
01537 forAll(curFace, fp)
01538 {
01539 bool inserted = facePoints.insert(curFace[fp]);
01540
01541 if (!inserted)
01542 {
01543 if (setPtr)
01544 {
01545 setPtr->insert(fI);
01546 }
01547
01548 nErrorFaces++;
01549 }
01550 }
01551 }
01552
01553 reduce(nErrorFaces, sumOp<label>());
01554
01555 if (nErrorFaces > 0)
01556 {
01557 if (debug || report)
01558 {
01559 Info<< " Faces with invalid vertex labels found, "
01560 << " number of faces: " << nErrorFaces << endl;
01561 }
01562
01563 return true;
01564 }
01565 else
01566 {
01567 if (debug || report)
01568 {
01569 Info<< " Face vertices OK." << endl;
01570 }
01571
01572 return false;
01573 }
01574 }
01575
01576
01577
01578 bool Foam::primitiveMesh::checkDuplicateFaces
01579 (
01580 const label faceI,
01581 const Map<label>& nCommonPoints,
01582 label& nBaffleFaces,
01583 labelHashSet* setPtr
01584 ) const
01585 {
01586 bool error = false;
01587
01588 forAllConstIter(Map<label>, nCommonPoints, iter)
01589 {
01590 label nbFaceI = iter.key();
01591 label nCommon = iter();
01592
01593 const face& curFace = faces()[faceI];
01594 const face& nbFace = faces()[nbFaceI];
01595
01596 if (nCommon == nbFace.size() || nCommon == curFace.size())
01597 {
01598 if (nbFace.size() != curFace.size())
01599 {
01600 error = true;
01601 }
01602 else
01603 {
01604 nBaffleFaces++;
01605 }
01606
01607 if (setPtr)
01608 {
01609 setPtr->insert(faceI);
01610 setPtr->insert(nbFaceI);
01611 }
01612 }
01613 }
01614
01615 return error;
01616 }
01617
01618
01619
01620 bool Foam::primitiveMesh::checkCommonOrder
01621 (
01622 const label faceI,
01623 const Map<label>& nCommonPoints,
01624 labelHashSet* setPtr
01625 ) const
01626 {
01627 bool error = false;
01628
01629 forAllConstIter(Map<label>, nCommonPoints, iter)
01630 {
01631 label nbFaceI = iter.key();
01632 label nCommon = iter();
01633
01634 const face& curFace = faces()[faceI];
01635 const face& nbFace = faces()[nbFaceI];
01636
01637 if
01638 (
01639 nCommon >= 2
01640 && nCommon != nbFace.size()
01641 && nCommon != curFace.size()
01642 )
01643 {
01644 forAll(curFace, fp)
01645 {
01646
01647 label nb = findIndex(nbFace, curFace[fp]);
01648
01649 if (nb != -1)
01650 {
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661 label fpPlus1 = curFace.fcIndex(fp);
01662 label fpMin1 = curFace.rcIndex(fp);
01663
01664
01665 label nbPlus1 = nbFace.fcIndex(nb);
01666 label nbMin1 = nbFace.rcIndex(nb);
01667
01668
01669
01670 label curInc = labelMax;
01671 label nbInc = labelMax;
01672
01673 if (nbFace[nbPlus1] == curFace[fpPlus1])
01674 {
01675 curInc = 1;
01676 nbInc = 1;
01677 }
01678 else if (nbFace[nbPlus1] == curFace[fpMin1])
01679 {
01680 curInc = -1;
01681 nbInc = 1;
01682 }
01683 else if (nbFace[nbMin1] == curFace[fpMin1])
01684 {
01685 curInc = -1;
01686 nbInc = -1;
01687 }
01688 else
01689 {
01690 curInc = 1;
01691 nbInc = -1;
01692 }
01693
01694
01695
01696 label curNb = nb;
01697 label curFp = fp;
01698
01699 do
01700 {
01701 curFp += curInc;
01702
01703 if (curFp >= curFace.size())
01704 {
01705 curFp = 0;
01706 }
01707 else if (curFp < 0)
01708 {
01709 curFp = curFace.size()-1;
01710 }
01711
01712 curNb += nbInc;
01713
01714 if (curNb >= nbFace.size())
01715 {
01716 curNb = 0;
01717 }
01718 else if (curNb < 0)
01719 {
01720 curNb = nbFace.size()-1;
01721 }
01722 } while (curFace[curFp] == nbFace[curNb]);
01723
01724
01725
01726
01727
01728 curInc = -curInc;
01729 nbInc = -nbInc;
01730
01731 for (label commonI = 0; commonI < nCommon; commonI++)
01732 {
01733 curFp += curInc;
01734
01735 if (curFp >= curFace.size())
01736 {
01737 curFp = 0;
01738 }
01739 else if (curFp < 0)
01740 {
01741 curFp = curFace.size()-1;
01742 }
01743
01744 curNb += nbInc;
01745
01746 if (curNb >= nbFace.size())
01747 {
01748 curNb = 0;
01749 }
01750 else if (curNb < 0)
01751 {
01752 curNb = nbFace.size()-1;
01753 }
01754
01755 if (curFace[curFp] != nbFace[curNb])
01756 {
01757 if (setPtr)
01758 {
01759 setPtr->insert(faceI);
01760 setPtr->insert(nbFaceI);
01761 }
01762
01763 error = true;
01764
01765 break;
01766 }
01767 }
01768
01769
01770
01771 break;
01772 }
01773 }
01774 }
01775 }
01776
01777 return error;
01778 }
01779
01780
01781
01782
01783 bool Foam::primitiveMesh::checkFaceFaces
01784 (
01785 const bool report,
01786 labelHashSet* setPtr
01787 ) const
01788 {
01789 if (debug)
01790 {
01791 Info<< "bool primitiveMesh::checkFaceFaces(const bool, labelHashSet*)"
01792 << " const: " << "checking face-face connectivity" << endl;
01793 }
01794
01795 const labelListList& pf = pointFaces();
01796
01797 label nBaffleFaces = 0;
01798 label nErrorDuplicate = 0;
01799 label nErrorOrder = 0;
01800 Map<label> nCommonPoints(100);
01801
01802 for (label faceI = 0; faceI < nFaces(); faceI++)
01803 {
01804 const face& curFace = faces()[faceI];
01805
01806
01807
01808 nCommonPoints.clear();
01809
01810 forAll(curFace, fp)
01811 {
01812 label pointI = curFace[fp];
01813
01814 const labelList& nbs = pf[pointI];
01815
01816 forAll(nbs, nbI)
01817 {
01818 label nbFaceI = nbs[nbI];
01819
01820 if (faceI < nbFaceI)
01821 {
01822
01823
01824 Map<label>::iterator fnd = nCommonPoints.find(nbFaceI);
01825
01826 if (fnd == nCommonPoints.end())
01827 {
01828
01829 nCommonPoints.insert(nbFaceI, 1);
01830 }
01831 else
01832 {
01833 fnd()++;
01834 }
01835 }
01836 }
01837 }
01838
01839
01840
01841
01842 if (checkDuplicateFaces(faceI, nCommonPoints, nBaffleFaces, setPtr))
01843 {
01844 nErrorDuplicate++;
01845 }
01846
01847
01848 if (checkCommonOrder(faceI, nCommonPoints, setPtr))
01849 {
01850 nErrorOrder++;
01851 }
01852 }
01853
01854 reduce(nBaffleFaces, sumOp<label>());
01855 reduce(nErrorDuplicate, sumOp<label>());
01856 reduce(nErrorOrder, sumOp<label>());
01857
01858 if (nBaffleFaces)
01859 {
01860 Info<< " Number of identical duplicate faces (baffle faces): "
01861 << nBaffleFaces << endl;
01862 }
01863
01864 if (nErrorDuplicate > 0 || nErrorOrder > 0)
01865 {
01866 if (nErrorDuplicate > 0)
01867 {
01868 Info<< " ***Number of duplicate (not baffle) faces found: "
01869 << nErrorDuplicate << endl;
01870 }
01871
01872 if (nErrorOrder > 0)
01873 {
01874 Info<< " ***Number of faces with non-consecutive shared points: "
01875 << nErrorOrder << endl;
01876 }
01877
01878 return true;
01879 }
01880 else
01881 {
01882 if (debug || report)
01883 {
01884 Info<< " Face-face connectivity OK." << endl;
01885 }
01886
01887 return false;
01888 }
01889 }
01890
01891
01892
01893 bool Foam::primitiveMesh::checkCellDeterminant
01894 (
01895 const bool report,
01896 labelHashSet* setPtr,
01897 const Vector<label>& meshD
01898 ) const
01899 {
01900 if (debug)
01901 {
01902 Info<< "bool primitiveMesh::checkCellDeterminant(const bool"
01903 << ", labelHashSet*) const: "
01904 << "checking for under-determined cells" << endl;
01905 }
01906
01907
01908 label nDims = 0;
01909 label twoD = -1;
01910 for (direction dir = 0; dir < vector::nComponents; dir++)
01911 {
01912 if (meshD[dir] == 1)
01913 {
01914 nDims++;
01915 }
01916 else
01917 {
01918 twoD = dir;
01919 }
01920 }
01921
01922
01923 const cellList& c = cells();
01924
01925 label nErrorCells = 0;
01926
01927 scalar minDet = GREAT;
01928 scalar sumDet = 0;
01929 label nSummed = 0;
01930
01931 if (nDims == 1)
01932 {
01933 minDet = 1;
01934 sumDet = c.size()*minDet;
01935 nSummed = c.size();
01936 }
01937 else
01938 {
01939 forAll (c, cellI)
01940 {
01941 const labelList& curFaces = c[cellI];
01942
01943
01944 scalar avgArea = 0;
01945
01946 label nInternalFaces = 0;
01947
01948 forAll(curFaces, i)
01949 {
01950 if (isInternalFace(curFaces[i]))
01951 {
01952 avgArea += mag(faceAreas()[curFaces[i]]);
01953
01954 nInternalFaces++;
01955 }
01956 }
01957
01958 if (nInternalFaces == 0)
01959 {
01960 if (setPtr)
01961 {
01962 setPtr->insert(cellI);
01963 }
01964
01965 nErrorCells++;
01966 }
01967 else
01968 {
01969 avgArea /= nInternalFaces;
01970
01971 symmTensor areaTensor(symmTensor::zero);
01972
01973 forAll(curFaces, i)
01974 {
01975 if (isInternalFace(curFaces[i]))
01976 {
01977 areaTensor += sqr(faceAreas()[curFaces[i]]/avgArea);
01978 }
01979 }
01980
01981 if (nDims == 2)
01982 {
01983
01984
01985 if (twoD == 0)
01986 {
01987 areaTensor.xx() = 1;
01988 }
01989 else if (twoD == 1)
01990 {
01991 areaTensor.yy() = 1;
01992 }
01993 else
01994 {
01995 areaTensor.zz() = 1;
01996 }
01997 }
01998
01999 scalar determinant = mag(det(areaTensor));
02000
02001 minDet = min(determinant, minDet);
02002 sumDet += determinant;
02003 nSummed++;
02004
02005 if (determinant < 1e-3)
02006 {
02007 if (setPtr)
02008 {
02009 setPtr->insert(cellI);
02010 }
02011
02012 nErrorCells++;
02013 }
02014 }
02015 }
02016 }
02017
02018 reduce(nErrorCells, sumOp<label>());
02019 reduce(minDet, minOp<scalar>());
02020 reduce(sumDet, sumOp<scalar>());
02021 reduce(nSummed, sumOp<label>());
02022
02023 if (debug || report)
02024 {
02025 if (nSummed > 0)
02026 {
02027 Info<< " Cell determinant (wellposedness) : minimum: " << minDet
02028 << " average: " << sumDet/nSummed
02029 << endl;
02030 }
02031 }
02032
02033 if (nErrorCells > 0)
02034 {
02035 if (debug || report)
02036 {
02037 Info<< " ***Cells with small determinant found, number of cells: "
02038 << nErrorCells << endl;
02039 }
02040
02041 return true;
02042 }
02043 else
02044 {
02045 if (debug || report)
02046 {
02047 Info<< " Cell determinant check OK." << endl;
02048 }
02049
02050 return false;
02051 }
02052
02053 return false;
02054 }
02055
02056
02057
02058
02059 bool Foam::primitiveMesh::checkTopology(const bool report) const
02060 {
02061 label noFailedChecks = 0;
02062
02063 if (checkPoints(report)) noFailedChecks++;
02064 if (checkUpperTriangular(report)) noFailedChecks++;
02065 if (checkCellsZipUp(report)) noFailedChecks++;
02066 if (checkFaceVertices(report)) noFailedChecks++;
02067 if (checkFaceFaces(report)) noFailedChecks++;
02068
02069
02070 if (noFailedChecks == 0)
02071 {
02072 if (debug || report)
02073 {
02074 Info<< " Mesh topology OK." << endl;
02075 }
02076
02077 return false;
02078 }
02079 else
02080 {
02081 if (debug || report)
02082 {
02083 Info<< " Failed " << noFailedChecks
02084 << " mesh topology checks." << endl;
02085 }
02086
02087 return true;
02088 }
02089 }
02090
02091
02092 bool Foam::primitiveMesh::checkGeometry(const bool report) const
02093 {
02094 label noFailedChecks = 0;
02095
02096 if (checkClosedBoundary(report)) noFailedChecks++;
02097 if (checkClosedCells(report)) noFailedChecks++;
02098 if (checkFaceAreas(report)) noFailedChecks++;
02099 if (checkCellVolumes(report)) noFailedChecks++;
02100 if (checkFaceOrthogonality(report)) noFailedChecks++;
02101 if (checkFacePyramids(report)) noFailedChecks++;
02102 if (checkFaceSkewness(report)) noFailedChecks++;
02103
02104 if (noFailedChecks == 0)
02105 {
02106 if (debug || report)
02107 {
02108 Info<< " Mesh geometry OK." << endl;
02109 }
02110 return false;
02111 }
02112 else
02113 {
02114 if (debug || report)
02115 {
02116 Info<< " Failed " << noFailedChecks
02117 << " mesh geometry checks." << endl;
02118 }
02119
02120 return true;
02121 }
02122 }
02123
02124
02125 bool Foam::primitiveMesh::checkMesh(const bool report) const
02126 {
02127 if (debug)
02128 {
02129 Info<< "bool primitiveMesh::checkMesh(const bool report) const: "
02130 << "checking primitiveMesh" << endl;
02131 }
02132
02133 label noFailedChecks = checkTopology(report) + checkGeometry(report);
02134
02135 if (noFailedChecks == 0)
02136 {
02137 if (debug || report)
02138 {
02139 Info<< "Mesh OK." << endl;
02140 }
02141
02142 return false;
02143 }
02144 else
02145 {
02146 if (debug || report)
02147 {
02148 Info<< " Failed " << noFailedChecks
02149 << " mesh checks." << endl;
02150 }
02151
02152 return true;
02153 }
02154 }
02155
02156
02157 Foam::scalar Foam::primitiveMesh::setClosedThreshold(const scalar val)
02158 {
02159 scalar prev = closedThreshold_;
02160 closedThreshold_ = val;
02161
02162 return prev;
02163 }
02164
02165
02166 Foam::scalar Foam::primitiveMesh::setAspectThreshold(const scalar val)
02167 {
02168 scalar prev = aspectThreshold_;
02169 aspectThreshold_ = val;
02170
02171 return prev;
02172 }
02173
02174
02175 Foam::scalar Foam::primitiveMesh::setNonOrthThreshold(const scalar val)
02176 {
02177 scalar prev = nonOrthThreshold_;
02178 nonOrthThreshold_ = val;
02179
02180 return prev;
02181 }
02182
02183
02184 Foam::scalar Foam::primitiveMesh::setSkewThreshold(const scalar val)
02185 {
02186 scalar prev = skewThreshold_;
02187 skewThreshold_ = val;
02188
02189 return prev;
02190 }
02191
02192
02193