00001 #include "checkGeometry.H"
00002 #include <OpenFOAM/polyMesh.H>
00003 #include <meshTools/cellSet.H>
00004 #include <meshTools/faceSet.H>
00005 #include <meshTools/pointSet.H>
00006 #include <OpenFOAM/EdgeMap.H>
00007 #include <OpenFOAM/wedgePolyPatch.H>
00008 #include <OpenFOAM/mathematicalConstants.H>
00009
00010
00011
00012
00013 Foam::label Foam::findOppositeWedge
00014 (
00015 const polyMesh& mesh,
00016 const wedgePolyPatch& wpp
00017 )
00018 {
00019 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00020
00021 scalar wppCosAngle = wpp.centreNormal()&wpp.patchNormal();
00022
00023 forAll(patches, patchI)
00024 {
00025 if
00026 (
00027 patchI != wpp.index()
00028 && patches[patchI].size()
00029 && isA<wedgePolyPatch>(patches[patchI])
00030 )
00031 {
00032 const wedgePolyPatch& pp = refCast<const wedgePolyPatch>
00033 (
00034 patches[patchI]
00035 );
00036
00037
00038 scalar ppCosAngle = wpp.centreNormal()&pp.patchNormal();
00039
00040 if
00041 (
00042 pp.size() == wpp.size()
00043 && mag(pp.axis() & wpp.axis()) >= (1-1E-3)
00044 && mag(ppCosAngle - wppCosAngle) >= 1E-3
00045 )
00046 {
00047 return patchI;
00048 }
00049 }
00050 }
00051 return -1;
00052 }
00053
00054
00055 bool Foam::checkWedges
00056 (
00057 const polyMesh& mesh,
00058 const bool report,
00059 const Vector<label>& directions,
00060 labelHashSet* setPtr
00061 )
00062 {
00063
00064 EdgeMap<label> edgesInError;
00065
00066 const pointField& p = mesh.points();
00067 const faceList& fcs = mesh.faces();
00068
00069
00070 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00071 forAll(patches, patchI)
00072 {
00073 if (patches[patchI].size() && isA<wedgePolyPatch>(patches[patchI]))
00074 {
00075 const wedgePolyPatch& pp = refCast<const wedgePolyPatch>
00076 (
00077 patches[patchI]
00078 );
00079
00080 scalar wedgeAngle = acos(pp.centreNormal()&pp.patchNormal());
00081
00082 if (report)
00083 {
00084 Info<< " Wedge " << pp.name() << " with angle "
00085 << 180/mathematicalConstant::pi*wedgeAngle << " degrees"
00086 << endl;
00087 }
00088
00089
00090 label oppositePatchI = findOppositeWedge(mesh, pp);
00091
00092 if (oppositePatchI == -1)
00093 {
00094 if (report)
00095 {
00096 Info<< " ***Cannot find opposite wedge for wedge "
00097 << pp.name() << endl;
00098 }
00099 return true;
00100 }
00101
00102 const wedgePolyPatch& opp = refCast<const wedgePolyPatch>
00103 (
00104 patches[oppositePatchI]
00105 );
00106
00107
00108 if (mag(opp.axis() & pp.axis()) < (1-1E-3))
00109 {
00110 if (report)
00111 {
00112 Info<< " ***Wedges do not have the same axis."
00113 << " Encountered " << pp.axis()
00114 << " on patch " << pp.name()
00115 << " which differs from " << opp.axis()
00116 << " on opposite wedge patch" << opp.axis()
00117 << endl;
00118 }
00119 return true;
00120 }
00121
00122
00123
00124
00125 forAll(pp, i)
00126 {
00127 const face& f = pp[i];
00128 forAll(f, fp)
00129 {
00130 label p0 = f[fp];
00131 label p1 = f.nextLabel(fp);
00132 edgesInError.insert(edge(p0, p1), -1);
00133 }
00134 }
00135
00136
00137
00138 const point& p0 = p[pp.meshPoints()[0]];
00139 forAll(pp.meshPoints(), i)
00140 {
00141 const point& pt = p[pp.meshPoints()[i]];
00142 scalar d = mag((pt-p0) & pp.patchNormal());
00143
00144 if (d > sqrt(SMALL))
00145 {
00146 if (report)
00147 {
00148 Info<< " ***Wedge patch " << pp.name() << " not planar."
00149 << " Point " << pt << " is not in patch plane by "
00150 << d << " meter."
00151 << endl;
00152 }
00153 return true;
00154 }
00155 }
00156 }
00157 }
00158
00159
00160
00161
00162 label nEdgesInError = 0;
00163
00164 forAll(fcs, faceI)
00165 {
00166 const face& f = fcs[faceI];
00167
00168 forAll(f, fp)
00169 {
00170 label p0 = f[fp];
00171 label p1 = f.nextLabel(fp);
00172 if (p0 < p1)
00173 {
00174 vector d(p[p1]-p[p0]);
00175 scalar magD = mag(d);
00176
00177 if (magD > ROOTVSMALL)
00178 {
00179 d /= magD;
00180
00181
00182 label nEmptyDirs = 0;
00183 label nNonEmptyDirs = 0;
00184 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
00185 {
00186 if (mag(d[cmpt]) > 1e-6)
00187 {
00188 if (directions[cmpt] == 0)
00189 {
00190 nEmptyDirs++;
00191 }
00192 else
00193 {
00194 nNonEmptyDirs++;
00195 }
00196 }
00197 }
00198
00199 if (nEmptyDirs == 0)
00200 {
00201
00202 }
00203 else if (nEmptyDirs == 1)
00204 {
00205
00206 if (nNonEmptyDirs > 0)
00207 {
00208 if (edgesInError.insert(edge(p0, p1), faceI))
00209 {
00210 nEdgesInError++;
00211 }
00212 }
00213 }
00214 else if (nEmptyDirs > 1)
00215 {
00216
00217 if (edgesInError.insert(edge(p0, p1), faceI))
00218 {
00219 nEdgesInError++;
00220 }
00221 }
00222 }
00223 }
00224 }
00225 }
00226
00227 label nErrorEdges = returnReduce(nEdgesInError, sumOp<label>());
00228
00229 if (nErrorEdges > 0)
00230 {
00231 if (report)
00232 {
00233 Info<< " ***Number of edges not aligned with or perpendicular to "
00234 << "non-empty directions: " << nErrorEdges << endl;
00235 }
00236
00237 if (setPtr)
00238 {
00239 setPtr->resize(2*nEdgesInError);
00240 forAllConstIter(EdgeMap<label>, edgesInError, iter)
00241 {
00242 if (iter() >= 0)
00243 {
00244 setPtr->insert(iter.key()[0]);
00245 setPtr->insert(iter.key()[1]);
00246 }
00247 }
00248 }
00249
00250 return true;
00251 }
00252 else
00253 {
00254 if (report)
00255 {
00256 Info<< " All edges aligned with or perpendicular to "
00257 << "non-empty directions." << endl;
00258 }
00259 return false;
00260 }
00261 }
00262
00263
00264 Foam::label Foam::checkGeometry(const polyMesh& mesh, const bool allGeometry)
00265 {
00266 label noFailedChecks = 0;
00267
00268 Info<< "\nChecking geometry..." << endl;
00269
00270
00271 const boundBox& globalBb = mesh.bounds();
00272
00273 Info<< " Overall domain bounding box "
00274 << globalBb.min() << " " << globalBb.max() << endl;
00275
00276
00277
00278 scalar minDistSqr = magSqr(1e-6 * globalBb.span());
00279
00280
00281 const Vector<label> validDirs = (mesh.geometricD() + Vector<label>::one)/2;
00282 Info<< " Mesh (non-empty, non-wedge) directions " << validDirs << endl;
00283
00284 const Vector<label> solDirs = (mesh.solutionD() + Vector<label>::one)/2;
00285 Info<< " Mesh (non-empty) directions " << solDirs << endl;
00286
00287 if (mesh.nGeometricD() < 3)
00288 {
00289 pointSet nonAlignedPoints(mesh, "nonAlignedEdges", mesh.nPoints()/100);
00290
00291 if
00292 (
00293 (
00294 validDirs != solDirs
00295 && checkWedges(mesh, true, validDirs, &nonAlignedPoints)
00296 )
00297 || (
00298 validDirs == solDirs
00299 && mesh.checkEdgeAlignment(true, validDirs, &nonAlignedPoints)
00300 )
00301 )
00302 {
00303 noFailedChecks++;
00304 label nNonAligned = returnReduce
00305 (
00306 nonAlignedPoints.size(),
00307 sumOp<label>()
00308 );
00309
00310 if (nNonAligned > 0)
00311 {
00312 Info<< " <<Writing " << nNonAligned
00313 << " points on non-aligned edges to set "
00314 << nonAlignedPoints.name() << endl;
00315 nonAlignedPoints.write();
00316 }
00317 }
00318 }
00319
00320 if (mesh.checkClosedBoundary(true)) noFailedChecks++;
00321
00322 {
00323 cellSet cells(mesh, "nonClosedCells", mesh.nCells()/100+1);
00324 cellSet aspectCells(mesh, "highAspectRatioCells", mesh.nCells()/100+1);
00325 if
00326 (
00327 mesh.checkClosedCells
00328 (
00329 true,
00330 &cells,
00331 &aspectCells,
00332 mesh.geometricD()
00333 )
00334 )
00335 {
00336 noFailedChecks++;
00337
00338 label nNonClosed = returnReduce(cells.size(), sumOp<label>());
00339
00340 if (nNonClosed > 0)
00341 {
00342 Info<< " <<Writing " << nNonClosed
00343 << " non closed cells to set " << cells.name() << endl;
00344 cells.write();
00345 }
00346 }
00347
00348 label nHighAspect = returnReduce(aspectCells.size(), sumOp<label>());
00349
00350 if (nHighAspect > 0)
00351 {
00352 Info<< " <<Writing " << nHighAspect
00353 << " cells with high aspect ratio to set "
00354 << aspectCells.name() << endl;
00355 aspectCells.write();
00356 }
00357 }
00358
00359 {
00360 faceSet faces(mesh, "zeroAreaFaces", mesh.nFaces()/100 + 1);
00361 if (mesh.checkFaceAreas(true, &faces))
00362 {
00363 noFailedChecks++;
00364
00365 label nFaces = returnReduce(faces.size(), sumOp<label>());
00366
00367 if (nFaces > 0)
00368 {
00369 Info<< " <<Writing " << nFaces
00370 << " zero area faces to set " << faces.name() << endl;
00371 faces.write();
00372 }
00373 }
00374 }
00375
00376 {
00377 cellSet cells(mesh, "zeroVolumeCells", mesh.nCells()/100 + 1);
00378 if (mesh.checkCellVolumes(true, &cells))
00379 {
00380 noFailedChecks++;
00381
00382 label nCells = returnReduce(cells.size(), sumOp<label>());
00383
00384 if (nCells > 0)
00385 {
00386 Info<< " <<Writing " << nCells
00387 << " zero volume cells to set " << cells.name() << endl;
00388 cells.write();
00389 }
00390 }
00391 }
00392
00393 {
00394 faceSet faces(mesh, "nonOrthoFaces", mesh.nFaces()/100 + 1);
00395 if (mesh.checkFaceOrthogonality(true, &faces))
00396 {
00397 noFailedChecks++;
00398 }
00399
00400 label nFaces = returnReduce(faces.size(), sumOp<label>());
00401
00402 if (nFaces > 0)
00403 {
00404 Info<< " <<Writing " << nFaces
00405 << " non-orthogonal faces to set " << faces.name() << endl;
00406 faces.write();
00407 }
00408 }
00409
00410
00411 {
00412 faceSet faces(mesh, "wrongOrientedFaces", mesh.nFaces()/100 + 1);
00413 if (mesh.checkFacePyramids(true, -SMALL, &faces))
00414 {
00415 noFailedChecks++;
00416
00417 label nFaces = returnReduce(faces.size(), sumOp<label>());
00418
00419 if (nFaces > 0)
00420 {
00421 Info<< " <<Writing " << nFaces
00422 << " faces with incorrect orientation to set "
00423 << faces.name() << endl;
00424 faces.write();
00425 }
00426 }
00427 }
00428
00429 {
00430 faceSet faces(mesh, "skewFaces", mesh.nFaces()/100 + 1);
00431 if (mesh.checkFaceSkewness(true, &faces))
00432 {
00433 noFailedChecks++;
00434
00435 label nFaces = returnReduce(faces.size(), sumOp<label>());
00436
00437 if (nFaces > 0)
00438 {
00439 Info<< " <<Writing " << nFaces
00440 << " skew faces to set " << faces.name() << endl;
00441 faces.write();
00442 }
00443 }
00444 }
00445
00446 if (allGeometry)
00447 {
00448
00449 pointSet points(mesh, "shortEdges", mesh.nPoints()/1000 + 1);
00450 if (mesh.checkEdgeLength(true, minDistSqr, &points))
00451 {
00452
00453
00454 label nPoints = returnReduce(points.size(), sumOp<label>());
00455
00456 if (nPoints > 0)
00457 {
00458 Info<< " <<Writing " << nPoints
00459 << " points on short edges to set " << points.name()
00460 << endl;
00461 points.write();
00462 }
00463 }
00464
00465 label nEdgeClose = returnReduce(points.size(), sumOp<label>());
00466
00467 if (mesh.checkPointNearness(false, minDistSqr, &points))
00468 {
00469
00470
00471 label nPoints = returnReduce(points.size(), sumOp<label>());
00472
00473 if (nPoints > nEdgeClose)
00474 {
00475 pointSet nearPoints(mesh, "nearPoints", points);
00476 Info<< " <<Writing " << nPoints
00477 << " near (closer than " << Foam::sqrt(minDistSqr)
00478 << " apart) points to set " << nearPoints.name() << endl;
00479 nearPoints.write();
00480 }
00481 }
00482 }
00483
00484 if (allGeometry)
00485 {
00486 faceSet faces(mesh, "concaveFaces", mesh.nFaces()/100 + 1);
00487 if (mesh.checkFaceAngles(true, 10, &faces))
00488 {
00489
00490
00491 label nFaces = returnReduce(faces.size(), sumOp<label>());
00492
00493 if (nFaces > 0)
00494 {
00495 Info<< " <<Writing " << nFaces
00496 << " faces with concave angles to set " << faces.name()
00497 << endl;
00498 faces.write();
00499 }
00500 }
00501 }
00502
00503 if (allGeometry)
00504 {
00505 faceSet faces(mesh, "warpedFaces", mesh.nFaces()/100 + 1);
00506 if (mesh.checkFaceFlatness(true, 0.8, &faces))
00507 {
00508
00509
00510 label nFaces = returnReduce(faces.size(), sumOp<label>());
00511
00512 if (nFaces > 0)
00513 {
00514 Info<< " <<Writing " << nFaces
00515 << " warped faces to set " << faces.name() << endl;
00516 faces.write();
00517 }
00518 }
00519 }
00520
00521 if (allGeometry)
00522 {
00523 cellSet cells(mesh, "underdeterminedCells", mesh.nCells()/100);
00524 if (mesh.checkCellDeterminant(true, &cells, mesh.geometricD()))
00525 {
00526 noFailedChecks++;
00527
00528 label nCells = returnReduce(cells.size(), sumOp<label>());
00529
00530 Info<< " <<Writing " << nCells
00531 << " under-determined cells to set " << cells.name() << endl;
00532 cells.write();
00533 }
00534 }
00535
00536
00537 return noFailedChecks;
00538 }
00539
00540