00001 #include "checkTopology.H"
00002 #include <OpenFOAM/polyMesh.H>
00003 #include <OpenFOAM/Time.H>
00004 #include <meshTools/regionSplit.H>
00005 #include <meshTools/cellSet.H>
00006 #include <meshTools/faceSet.H>
00007 #include <meshTools/pointSet.H>
00008 #include <OpenFOAM/IOmanip.H>
00009
00010 bool Foam::checkSync(const wordList& names)
00011 {
00012 List<wordList> allNames(Pstream::nProcs());
00013 allNames[Pstream::myProcNo()] = names;
00014 Pstream::gatherList(allNames);
00015 Pstream::scatterList(allNames);
00016
00017 bool hasError = false;
00018
00019 for (label procI = 1; procI < allNames.size(); procI++)
00020 {
00021 if (allNames[procI] != allNames[0])
00022 {
00023 hasError = true;
00024
00025 Info<< " ***Inconsistent zones across processors, "
00026 "processor 0 has zones:" << allNames[0]
00027 << ", processor " << procI << " has zones:"
00028 << allNames[procI]
00029 << endl;
00030 }
00031 }
00032 return hasError;
00033 }
00034
00035
00036 Foam::label Foam::checkTopology
00037 (
00038 const polyMesh& mesh,
00039 const bool allTopology,
00040 const bool allGeometry
00041 )
00042 {
00043 label noFailedChecks = 0;
00044
00045 Info<< "Checking topology..." << endl;
00046
00047
00048 mesh.boundaryMesh().checkDefinition(true);
00049
00050
00051 mesh.boundaryMesh().checkParallelSync(true);
00052
00053
00054 if (checkSync(mesh.cellZones().names()))
00055 {
00056 noFailedChecks++;
00057 }
00058 if (checkSync(mesh.faceZones().names()))
00059 {
00060 noFailedChecks++;
00061 }
00062 if (checkSync(mesh.pointZones().names()))
00063 {
00064 noFailedChecks++;
00065 }
00066
00067
00068 {
00069 forAll(mesh.faceZones(), zoneI)
00070 {
00071 if (mesh.faceZones()[zoneI].checkParallelSync(false))
00072 {
00073 Info<< " ***FaceZone " << mesh.faceZones()[zoneI].name()
00074 << " is not correctly synchronised"
00075 << " across coupled boundaries."
00076 << " (coupled faces are either not both "
00077 << " present in set or have same flipmap)" << endl;
00078 noFailedChecks++;
00079 }
00080 }
00081 }
00082
00083 {
00084 pointSet points(mesh, "unusedPoints", mesh.nPoints()/100);
00085 if (mesh.checkPoints(true, &points))
00086 {
00087 noFailedChecks++;
00088
00089 label nPoints = returnReduce(points.size(), sumOp<label>());
00090
00091 Info<< " <<Writing " << nPoints
00092 << " unused points to set " << points.name() << endl;
00093 points.write();
00094 }
00095 }
00096
00097 {
00098 faceSet faces(mesh, "upperTriangularFace", mesh.nFaces()/100);
00099 if (mesh.checkUpperTriangular(true, &faces))
00100 {
00101 noFailedChecks++;
00102 }
00103
00104 label nFaces = returnReduce(faces.size(), sumOp<label>());
00105
00106 if (nFaces > 0)
00107 {
00108 Info<< " <<Writing " << nFaces
00109 << " unordered faces to set " << faces.name() << endl;
00110 faces.write();
00111 }
00112 }
00113
00114 if (allTopology)
00115 {
00116 cellSet cells(mesh, "zipUpCells", mesh.nCells()/100);
00117 if (mesh.checkCellsZipUp(true, &cells))
00118 {
00119 noFailedChecks++;
00120
00121 label nCells = returnReduce(cells.size(), sumOp<label>());
00122
00123 Info<< " <<Writing " << nCells
00124 << " cells with over used edges to set " << cells.name()
00125 << endl;
00126 cells.write();
00127 }
00128 }
00129
00130 {
00131 faceSet faces(mesh, "outOfRangeFaces", mesh.nFaces()/100);
00132 if (mesh.checkFaceVertices(true, &faces))
00133 {
00134 noFailedChecks++;
00135
00136 label nFaces = returnReduce(faces.size(), sumOp<label>());
00137
00138 Info<< " <<Writing " << nFaces
00139 << " faces with out-of-range or duplicate vertices to set "
00140 << faces.name() << endl;
00141 faces.write();
00142 }
00143 }
00144
00145 if (allTopology)
00146 {
00147 faceSet faces(mesh, "edgeFaces", mesh.nFaces()/100);
00148 if (mesh.checkFaceFaces(true, &faces))
00149 {
00150 noFailedChecks++;
00151
00152 label nFaces = returnReduce(faces.size(), sumOp<label>());
00153
00154 Info<< " <<Writing " << nFaces
00155 << " faces with incorrect edges to set " << faces.name()
00156 << endl;
00157 faces.write();
00158 }
00159 }
00160
00161 if (allTopology)
00162 {
00163 labelList nInternalFaces(mesh.nCells(), 0);
00164
00165 for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
00166 {
00167 nInternalFaces[mesh.faceOwner()[faceI]]++;
00168 nInternalFaces[mesh.faceNeighbour()[faceI]]++;
00169 }
00170 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00171 forAll(patches, patchI)
00172 {
00173 if (patches[patchI].coupled())
00174 {
00175 const unallocLabelList& owners = patches[patchI].faceCells();
00176
00177 forAll(owners, i)
00178 {
00179 nInternalFaces[owners[i]]++;
00180 }
00181 }
00182 }
00183
00184 cellSet oneCells(mesh, "oneInternalFaceCells", mesh.nCells()/100);
00185 cellSet twoCells(mesh, "twoInternalFacesCells", mesh.nCells()/100);
00186
00187 forAll(nInternalFaces, cellI)
00188 {
00189 if (nInternalFaces[cellI] <= 1)
00190 {
00191 oneCells.insert(cellI);
00192 }
00193 else if (nInternalFaces[cellI] == 2)
00194 {
00195 twoCells.insert(cellI);
00196 }
00197 }
00198
00199 label nOneCells = returnReduce(oneCells.size(), sumOp<label>());
00200
00201 if (nOneCells > 0)
00202 {
00203 Info<< " <<Writing " << nOneCells
00204 << " cells with with single non-boundary face to set "
00205 << oneCells.name()
00206 << endl;
00207 oneCells.write();
00208 }
00209
00210 label nTwoCells = returnReduce(twoCells.size(), sumOp<label>());
00211
00212 if (nTwoCells > 0)
00213 {
00214 Info<< " <<Writing " << nTwoCells
00215 << " cells with with single non-boundary face to set "
00216 << twoCells.name()
00217 << endl;
00218 twoCells.write();
00219 }
00220 }
00221
00222 {
00223 regionSplit rs(mesh);
00224
00225 if (rs.nRegions() == 1)
00226 {
00227 Info<< " Number of regions: " << rs.nRegions() << " (OK)."
00228 << endl;
00229
00230 }
00231 else
00232 {
00233 Info<< " *Number of regions: " << rs.nRegions() << endl;
00234
00235 Info<< " The mesh has multiple regions which are not connected "
00236 "by any face." << endl
00237 << " <<Writing region information to "
00238 << mesh.time().timeName()/"cellToRegion"
00239 << endl;
00240
00241 labelIOList ctr
00242 (
00243 IOobject
00244 (
00245 "cellToRegion",
00246 mesh.time().timeName(),
00247 mesh,
00248 IOobject::NO_READ,
00249 IOobject::NO_WRITE
00250 ),
00251 rs
00252 );
00253 ctr.write();
00254 }
00255 }
00256
00257 if (!Pstream::parRun())
00258 {
00259 Pout<< "\nChecking patch topology for multiply connected surfaces ..."
00260 << endl;
00261
00262 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00263
00264
00265 pointSet points
00266 (
00267 mesh,
00268 "nonManifoldPoints",
00269 mesh.nPoints()/100
00270 );
00271
00272 Pout.setf(ios_base::left);
00273
00274 Pout<< " "
00275 << setw(20) << "Patch"
00276 << setw(9) << "Faces"
00277 << setw(9) << "Points"
00278 << setw(34) << "Surface topology";
00279 if (allGeometry)
00280 {
00281 Pout<< " Bounding box";
00282 }
00283 Pout<< endl;
00284
00285 forAll(patches, patchI)
00286 {
00287 const polyPatch& pp = patches[patchI];
00288
00289 Pout<< " "
00290 << setw(20) << pp.name()
00291 << setw(9) << pp.size()
00292 << setw(9) << pp.nPoints();
00293
00294
00295 primitivePatch::surfaceTopo pTyp = pp.surfaceType();
00296
00297 if (pp.empty())
00298 {
00299 Pout<< setw(34) << "ok (empty)";
00300 }
00301 else if (pTyp == primitivePatch::MANIFOLD)
00302 {
00303 if (pp.checkPointManifold(true, &points))
00304 {
00305 Pout<< setw(34) << "multiply connected (shared point)";
00306 }
00307 else
00308 {
00309 Pout<< setw(34) << "ok (closed singly connected)";
00310 }
00311
00312
00313 pp.checkTopology(false, &points);
00314 }
00315 else
00316 {
00317 pp.checkTopology(false, &points);
00318
00319 if (pTyp == primitivePatch::OPEN)
00320 {
00321 Pout<< setw(34) << "ok (non-closed singly connected)";
00322 }
00323 else
00324 {
00325 Pout<< setw(34) << "multiply connected (shared edge)";
00326 }
00327 }
00328
00329 if (allGeometry)
00330 {
00331 const pointField& pts = pp.points();
00332 const labelList& mp = pp.meshPoints();
00333
00334 if (returnReduce(mp.size(), sumOp<label>()) > 0)
00335 {
00336 boundBox bb(point::max, point::min);
00337 forAll(mp, i)
00338 {
00339 bb.min() = min(bb.min(), pts[mp[i]]);
00340 bb.max() = max(bb.max(), pts[mp[i]]);
00341 }
00342 reduce(bb.min(), minOp<vector>());
00343 reduce(bb.max(), maxOp<vector>());
00344 Pout<< ' ' << bb;
00345 }
00346 }
00347 Pout<< endl;
00348 }
00349
00350 if (points.size())
00351 {
00352 Pout<< " <<Writing " << points.size()
00353 << " conflicting points to set "
00354 << points.name() << endl;
00355
00356 points.write();
00357 }
00358
00359
00360 }
00361
00362
00363
00364 if (allTopology)
00365 {
00366 mesh.cells();
00367 mesh.faces();
00368 mesh.edges();
00369 mesh.points();
00370 mesh.faceOwner();
00371 mesh.faceNeighbour();
00372 mesh.cellCells();
00373 mesh.edgeCells();
00374 mesh.pointCells();
00375 mesh.edgeFaces();
00376 mesh.pointFaces();
00377 mesh.cellEdges();
00378 mesh.faceEdges();
00379 mesh.pointEdges();
00380 }
00381
00382 return noFailedChecks;
00383 }