void getVolumeFromFaces ( RegionMesh const& mesh, Real vols[ 3 ], std::ostream& err = std::cerr ) { MeshUtility::GetCoordComponent getx ( 0 ); MeshUtility::GetCoordComponent gety ( 1 ); MeshUtility::GetCoordComponent getz ( 2 ); vols[ 0 ] = 0.0; vols[ 1 ] = 0.0; vols[ 2 ] = 0.0; typedef typename RegionMesh::facetShape_Type GeoBShape; typedef typename RegionMesh::facet_Type facet_Type; typedef boost::shared_ptr<CurrentFEManifold> current_fe_type; current_fe_type bdfe; switch ( GeoBShape::S_shape ) { case TRIANGLE: bdfe = current_fe_type ( new CurrentFEManifold ( feTriaP1, geoLinearTria, quadRuleTria1pt ) ); for ( ID i = 0; i < mesh.numBFaces(); i++ ) { bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES ); vols[ 0 ] += bdfe->normalIntegral ( getx ); vols[ 1 ] += bdfe->normalIntegral ( gety ); vols[ 2 ] += bdfe->normalIntegral ( getz ); } break; case QUAD: bdfe = current_fe_type ( new CurrentFEManifold ( feQuadQ1, geoBilinearQuad, quadRuleQuad1pt ) ); for ( ID i = 0; i < mesh.numBFaces(); i++ ) { bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES ); vols[ 0 ] += bdfe->normalIntegral ( getx ); vols[ 1 ] += bdfe->normalIntegral ( gety ); vols[ 2 ] += bdfe->normalIntegral ( getz ); } break; default: err << "Only tria and quad surface elements may be checked for volume orientation at the moment" << std::endl; ASSERT0 ( false, "ABORT CONDITION OCCURRED" ); } }
Real testClosedDomain ( RegionMesh const& mesh, std::ostream& err = std::cerr ) { typedef typename RegionMesh::facet_Type facet_Type; typedef boost::shared_ptr<CurrentFEManifold> current_fe_type; current_fe_type bdfe; MeshUtility::GetOnes ones; Real test ( 0.0 ); switch ( RegionMesh::facetShape_Type::S_shape ) { case TRIANGLE: bdfe = current_fe_type ( new CurrentFEManifold ( feTriaP1, geoLinearTria, quadRuleTria1pt ) ); for ( ID i = 0; i < mesh.numBFaces(); i++ ) { bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES ); test += bdfe->normalIntegral ( ones ); } break; case QUAD: bdfe = current_fe_type ( new CurrentFEManifold ( feQuadQ1, geoBilinearQuad, quadRuleQuad1pt ) ); for ( ID i = 0; i < mesh.numBFaces(); i++ ) { bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES ); test += bdfe->normalIntegral ( ones ); } break; default: err << "Only tria and quad surface elements may be checked for volume orientation at the moment" << std::endl; ASSERT0 ( false, "ABORT CONDITION OCCURRED" ); } return test; }
bool checkMesh3D ( RegionMesh& mesh, Switch& sw, bool fix = true, bool verbose = false, std::ostream& out = std::cerr, std::ostream& err = std::cerr, std::ostream& clog = std::clog ) { verbose = verbose && ( mesh.comm()->MyPID() == 0 ); typedef typename RegionMesh::point_Type point_Type; if ( mesh.storedPoints() == 0 ) { err << "FATAL: mesh does not store points: I cannot do anything" << std::endl; sw.create ( "ABORT_CONDITION", true ); sw.create ( "NOT_HAS_POINTS", true ); return false; } if (verbose) { out << " Check point marker ids" << std::endl; } if ( !MeshUtility::checkIsMarkerSet ( mesh.pointList ) ) { if (verbose) { err << "WARNING: Not all points have marker id set" << std::endl; } sw.create ( "POINTS_MARKER_UNSET", true ); } //------------------------------------------------------------------------- // VOLUMES //------------------------------------------------------------------------- if ( mesh.storedVolumes() == 0 ) { if (verbose) err << "FATAL: mesh does not store volumes: I cannot do anything" << std::endl; sw.create ( "ABORT_CONDITION", true ); sw.create ( "NOT_HAS_VOLUMES", true ); return false; } if ( !MeshUtility::checkId ( mesh.volumeList ) ) { if (verbose) { err << "ERROR: volume ids were wrongly set" << std::endl; err << "FIXED" << std::endl; } if ( fix ) { sw.create ( "FIXED_VOLUMES_ID", true ); } if ( fix ) { MeshUtility::fixId ( mesh.volumeList ); } } if (verbose) { out << " Check volum marker ids" << std::endl; } if ( !MeshUtility::checkIsMarkerSet ( mesh.volumeList ) ) { if (verbose) { err << "WARNING: Not all volumes have marker flag set" << std::endl; } sw.create ( "VOLUMES_MARKER_UNSET", true ); if ( fix ) { if (verbose) { out << "Fixing volume marker ids" << std::endl; } for ( typename RegionMesh::volumes_Type::iterator iv = mesh.volumeList.begin(); iv != mesh.volumeList.end(); ++iv ) { if ( iv->isMarkerUnset() ) { iv->setMarkerID ( mesh.markerID() ); } } } } if ( mesh.numElements() < mesh.storedVolumes() ) { if (verbose) err << "WARNING: Mesh Volumes must be at least " << mesh.storedVolumes() << std::endl; if ( fix ) { mesh.setNumVolumes ( mesh.storedVolumes() ); } if ( fix ) { sw.create ( "FIXED_VOLUME_COUNTER", true ); } } // test now orientation boost::shared_ptr<std::vector<bool> > elSign ( new std::vector<bool> ); Real meshMeasure = checkVolumes ( mesh, *elSign, sw ); UInt positive; if ( sw.test ( "SKIP_ORIENTATION_TEST" ) ) { if (verbose) { clog << "W: ELEMENT ORIENTATION NOT IMPLEMENTED YET FOR THIS TYPE OF ELEMENTS, SKIP" << std::endl; err << "W: ELEMENT ORIENTATION NOT IMPLEMENTED YET FOR THIS TYPE OF ELEMENTS, SKIP" << std::endl; } } else if ( sw.test ( "HAS_NEGATIVE_VOLUMES" ) ) { if (verbose) { out << "Checking volume orientation" << std::endl; } positive = count ( elSign->begin(), elSign->end(), true ); if ( verbose ) clog << positive << "W: positive elements out of" << mesh.storedVolumes() << std::endl; if ( fix ) { if ( verbose ) { clog << "Fixing negative elements" << std::endl; } fixVolumes ( mesh, *elSign, sw ); } if ( sw.test ( "ABORT_CONDITION" ) ) { if (verbose) err << "ABORT: Cannot fix volumes, this element is not supported" << std::endl; return false; } else { sw.unset ( "HAS_NEGATIVE_VOLUMES" ); meshMeasure = checkVolumes ( mesh, *elSign, sw ); if ( sw.test ( "HAS_NEGATIVE_VOLUMES" ) ) { if ( fix ) { if ( verbose ) { err << "ABORT: Cannot fix volumes: something wrong with this mesh" << std::endl; } sw.create ( "ABORT_CONDITION", true ); } return false; } } } if ( verbose ) clog << "Volume enclosed by the mesh= " << meshMeasure << std::endl << "(Computed by integrating mesh elements measures)" << std::endl << "(Using 1 point Quadrature rule)" << std::endl; //----------------------------------------------------- // BOUNDARY FACES //----------------------------------------------------- boost::shared_ptr<MeshUtility::temporaryFaceContainer_Type> bfaces ( new MeshUtility::temporaryFaceContainer_Type ); UInt numInternalFaces, numFaces; if (verbose) { out << "Finding boundary faces from mesh topology" << std::endl; } UInt bFacesFound = MeshUtility::findBoundaryFaces ( mesh, *bfaces, numInternalFaces ); numFaces = bFacesFound + numInternalFaces; MeshUtility::EnquireBFace<RegionMesh> enquireBFace (*bfaces ); UInt meshNumBoundaryFaces ( mesh.numBFaces() + mesh.faceList.countElementsWithFlag ( EntityFlags::SUBDOMAIN_INTERFACE, &Flag::testOneSet ) ); if ( mesh.storedFaces() == 0 || meshNumBoundaryFaces > mesh.storedFaces() || bFacesFound > mesh.storedFaces() || bFacesFound > meshNumBoundaryFaces ) { // Something strange with boundary faces if (verbose) { err << "ERROR: Not all boundary faces stored" << std::endl; err << "Found " << bFacesFound << " stored " << mesh.storedFaces() << "B faces declared in mesh " << meshNumBoundaryFaces << std::endl; } if ( fix ) { sw.create ( "BUILD_BFACES", true ); if (verbose) { out << "Building boundary faces from topology data" << std::endl; } MeshUtility::buildFaces ( mesh, clog, err, bFacesFound, numInternalFaces, true, false, false, bfaces.get() ); } if (verbose) { err << "After buildFaces" << std::endl; err << "Found " << bFacesFound << " stored " << mesh.storedFaces() << "B faces declared in mesh " << meshNumBoundaryFaces << std::endl; } } else { if ( mesh.storedFaces() == 0 ) { if ( verbose ) { err << "ABORT CONDITION: cannot find boundary faces" << std::endl; } sw.create ( "NOT_HAS_FACES", true ); sw.create ( "ABORT_CONDITION", true ); } // The mesh declares to have the correct boundary faces. Yet, are we sure that the flag has been properly set // and that they are stored first? If fix is set we don't trust anybody! // // Make sure that flags are set using the info in bfaces, which depends ONLY on the mesh topology. No messing bout with markers // Make sure BFaces are stored first if (fix) { if (verbose) { out << "Rearranging faces so that boundary faces are first" << std::endl; } MeshUtility::rearrangeFaces ( mesh, clog, err, sw, numFaces, bFacesFound, verbose, bfaces.get() ); } if ( meshNumBoundaryFaces != bFacesFound) { if ( verbose ) { err << " ERROR: Number of B faces does not correspond to real one" << std::endl; } if (fix) { if ( verbose ) { err << "FIXED Number of B faces has been fixed to:" << bFacesFound << std::endl; } mesh.setNumBFaces ( bFacesFound); } } if ( !MeshUtility::checkId ( mesh.faceList ) ) { if ( verbose ) { err << "ERROR: face ids were wrongly set" << std::endl; err << "FIXED" << std::endl; } if ( fix ) { sw.create ( "FIXED_FACES_ID", true ); MeshUtility::fixId ( mesh.faceList ); } } // Check Consistency with the mesh. if ( fix ) { if (verbose) { out << "Make sure that adjacent elements of boundary faces are correct" << std::endl; } MeshUtility::fixBoundaryFaces ( mesh, clog, err, sw, numFaces, bFacesFound, false, verbose, bfaces.get() ); } if ( mesh.numBFaces() == 0 ) { if ( verbose ) { err << " MeshBFaces counter is unset" << std::endl; } if ( fix ) { mesh.setNumBFaces ( mesh.storedFaces() ); sw.create ( "FIXED_BFACE_COUNTER", true ); mesh.setLinkSwitch ( "HAS_BOUNDARY_FACETS" ); } } if ( !MeshUtility::checkIsMarkerSet ( mesh.faceList ) ) { if (verbose) { out << "Fix markers id for faces" << std::endl; } if ( verbose ) { err << "WARNING: Not all faces have marker flag set" << std::endl; } sw.create ( "FACE_MARKER_UNSET", true ); if ( fix ) { MeshUtility::setBoundaryFacesMarker ( mesh, clog, err, verbose ); } if ( fix && MeshUtility::checkIsMarkerSet ( mesh.faceList ) ) { sw.create ( "FACE_MARKER_UNSET", false ); sw.create ( "FACE_MARKER_FIXED", true ); } } } if ( mesh.numFaces() != bFacesFound + numInternalFaces ) { if ( verbose ) { err << "WARNING Number of faces incorrectly set" << std::endl; err << " It was " << mesh.numFaces() << std::endl; err << " It should be " << bFacesFound + numInternalFaces << std::endl; } if ( fix ) { if ( verbose ) { err << " Fixing" << std::endl; } mesh.setNumFaces ( bFacesFound + numInternalFaces ); sw.create ( "FIXED_FACE_COUNTER", true ); } } if ( fix && mesh.storedFaces() == bFacesFound + numInternalFaces) { mesh.setLinkSwitch ( "HAS_ALL_FACETS" ); } if (verbose) { out << std::endl; out << " Boundary faces found :" << bFacesFound << std::endl; out << " Num Faces Stored stored :" << mesh.storedFaces() << std::endl; out << " Num faces in mesh :" << mesh.numFaces() << std::endl; out << " Boundary faces counter gives:" << mesh.numBFaces() << std::endl; out << std::endl; } //----------------------------------------------------- // BOUNDARY EDGES //----------------------------------------------------- boost::shared_ptr<MeshUtility::temporaryEdgeContainer_Type> bedges ( new MeshUtility::temporaryEdgeContainer_Type ); UInt bEdgesFound = MeshUtility::findBoundaryEdges ( mesh, *bedges ); MeshUtility::EnquireBEdge<RegionMesh> enquireBEdge (*bedges ); UInt intedge (0); UInt Ned (0); MeshUtility::temporaryEdgeContainer_Type iedges; if ( mesh.storedEdges() == 0 || mesh.numBEdges() > mesh.storedEdges() || bEdgesFound > mesh.storedEdges() ) { if (verbose) { err << "WARNING: mesh does not store (all) boundary edges" << std::endl; } sw.create ( "NOT_HAS_EDGES", true ); if ( fix ) { if (verbose) { out << "Build boundary edges" << std::endl; } MeshUtility::buildEdges ( mesh, clog, err, bEdgesFound, intedge, true, false, false, bedges.get() ); } Ned = bEdgesFound + intedge; if ( fix ) { sw.create ( "BUILD_BEDGES", true ); } } else { // Make sure BEdges are first // Here I need to use a method that does not require the proper // setting of boundary Points! // With the edges I am being a bit sloppy. I am trusting the given mesh // todo do the same it was done for faces! if ( mesh.numBEdges() != bEdgesFound) { if ( verbose ) { err << " ERROR: Number of BEdges does not correspond to real one" << std::endl; } if (fix) { if ( verbose ) { err << "FIXED Number of BEdges has been fixed to:" << bEdgesFound << std::endl; } mesh.setNumBEdges ( bEdgesFound); } } if ( fix ) { if (verbose) { out << "Reorder edges so that boundary are first" << std::endl; } mesh.edgeList.reorderAccordingToFlag (EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet); sw.create ( "FIXED_BEDGES_FIRST" ); } if ( !MeshUtility::checkId ( mesh.edgeList ) ) { if ( verbose ) { err << "ERROR: edge ids were wrongly set" << std::endl; } if (fix) { if ( verbose ) { err << "FIXED" << std::endl; } sw.create ( "FIXED_EDGES_ID", true ); MeshUtility::fixId ( mesh.edgeList ); } } if ( !MeshUtility::checkIsMarkerSet ( mesh.edgeList ) ) { if ( verbose ) { err << "WARNING: Not all edges have marker flag set" << std::endl; } sw.create ( "EDGE_MARKER_UNSET", true ); if ( fix ) { if (verbose) { out << "Fix boundary edges marker" << std::endl; } MeshUtility::setBoundaryEdgesMarker ( mesh, clog, err, verbose ); } if ( fix && MeshUtility::checkIsMarkerSet ( mesh.edgeList ) ) { sw.unset ( "EDGE_MARKER_UNSET" ); sw.create ( "EDGE_MARKER_FIXED", true ); } } if (verbose) { out << "Computing number of internal edges"; } if ( fix ) { Ned = bEdgesFound + MeshUtility::findInternalEdges ( mesh, *bedges, iedges ); } } iedges.clear(); MeshUtility::temporaryEdgeContainer_Type tmp; iedges.swap (tmp); if ( mesh.numBEdges() != bEdgesFound ) { if ( verbose ) err << "WARNING: number of found boundary edges:" << bEdgesFound << std::endl << " does not match that declared in mesh, i.e. " << mesh.numBEdges() << std::endl; if ( mesh.numBEdges() == 0 ) { if ( fix ) { if ( verbose ) { err << "FIXING" << std::endl; } sw.create ( "FIXED_BEDGES_COUNTER", true ); mesh.setNumBEdges ( bEdgesFound ); } } } if ( Ned != mesh.numEdges() ) { if ( fix ) { if ( verbose ) err << "WARNING: Counter of number of edges badly set: Should be (actual number)" << Ned << std::endl << "It is instead equal to " << mesh.numEdges() << std::endl; err << " **FIXED" << std::endl; mesh.setNumEdges ( Ned ); } } UInt nbed; UInt counte = MeshUtility::testDomainTopology ( mesh, nbed ); if ( counte == 0 ) { if ( verbose ) { out << "**DOMAIN SURFACE IS (TOPOLOGICALLY) CLOSED" << std::endl; } } else { sw.create ( "DOMAIN_NOT_CLOSED", true ); if ( verbose ) err << "WARNING: DOMAIN APPEARS TO HAVE AN OPEN BOUNDARY (TOPOLOGY CHECK)" << std::endl << "Number of inconsistent edges:" << counte << std::endl; } //----------------------------------------------------- // POINTS //----------------------------------------------------- if (verbose) { out << "Checking vertexes" << std::endl; } UInt numVerticesFound = mesh.pointList.countElementsWithFlag (EntityFlags::VERTEX, &Flag::testOneSet); if (numVerticesFound != mesh.numVertices() ) { if ( verbose ) { err << "warning: The number of Points with vertex flag on does not coincide with the declared one." << std::endl; } if (fix) { if ( verbose ) { err << "It will be fixed now" << std::endl; } // unset the flag. It will be remade for (UInt i = 0; i < mesh.numPoints(); ++i) { mesh.point (i).unSetFlag (EntityFlags::VERTEX); } // Find the real vertices and set the flag for (UInt i = 0; i < mesh.numElements(); ++i) for (UInt j = 0; j < mesh.numLocalVertices(); ++j) { ID k = mesh.element (i).point (j).localId(); mesh.pointList (k).setFlag (EntityFlags::VERTEX); } numVerticesFound = mesh.pointList.countElementsWithFlag ( EntityFlags::VERTEX, &Flag::testOneSet); mesh.setNumVertices (numVerticesFound); UInt numBVerticesFound = mesh.pointList.countElementsWithFlag ( EntityFlags::VERTEX | EntityFlags::PHYSICAL_BOUNDARY, &Flag::testAllSet); mesh.setNumBVertices (numBVerticesFound); sw.create ( "FIXED_VERTICES_COUNTER", true ); } } // Now that boundary faces have been correctly set we may work out // boundaty points if (fix) { if (verbose) { out << "Fix boundary points using boundary faces info" << std::endl; } MeshUtility::fixBoundaryPoints (mesh, clog, err, verbose); } MeshUtility::EnquireBPoint<RegionMesh> enquirebpoint ( mesh ); UInt foundBPoints = mesh.pointList.countElementsWithFlag (EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet); if (verbose) { out << "B Points Found " << foundBPoints << std::endl; } if ( foundBPoints == 0 || foundBPoints < mesh.storedBPoints() ) { if ( verbose ) { err << "ERROR Bpoints indicator not correctly set" << std::endl; } } else { if ( fix ) { sw.create ( "FIXED_BOUNDARY_POINTS", true ); } } // Now that we are sure that (jus) boundary points are flagged as such we check if the marker id is set if (verbose) { out << "Chsck point marker Ids" << std::endl; } if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) ) { if (verbose) { err << "Points MARKER id incorrectly set" << std::endl; } if ( fix ) { if ( verbose ) { err << " Fixing Points Marker ID" << std::endl << "If unset the boundary will inherit the strongest among faces" << std::endl; } if ( verbose ) { err << " The internal will be set to the domain flag" << std::endl; } MeshUtility::setBoundaryPointsMarker ( mesh, clog, err, false ); // fix marker at interior points. It takes if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) ) { // Maybe boundary points marker is fine, this is enough bool boundaryIsOk (true); std::vector<point_Type const*> listOfPt = mesh.pointList.extractElementsWithFlag ( EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet); for (typename std::vector<point_Type const*>::const_iterator it = listOfPt.begin(); it < listOfPt.end(); ++it) { boundaryIsOk = boundaryIsOk | (*it)->isMarkerSet(); } std::vector<point_Type const*>().swap (listOfPt); // save memory if ( verbose ) { clog << " Marker ID on boundary points is fine. Internal points may have marker unset" << std::endl; } if (verbose) { err << "Cannot Fix Points MARKER" << std::endl; } if ( verbose && boundaryIsOk ) { err << "But boundary points are fine" << std::endl; } sw.create ( "POINT_MARKER_UNSET", true ); } else { if (verbose) { err << "FIXED" << std::endl; } sw.create ( "FIXED_POINT_MARKER", true ); } } } if ( mesh.storedBPoints() == 0 ) { if ( verbose ) { err << "WARNING B. Points COUNTER incorrectly set" << std::endl; } if ( fix ) { MeshUtility::setBoundaryPointsCounters ( mesh ) ; if ( verbose ) { err << " FIXED" << std::endl; } sw.create ( "FIXED_BPOINTS_COUNTER", true ); } } if ( mesh.numPoints() == 0 ) { if ( verbose ) { err << "WARNING Points Counter unset" << std::endl; } if ( fix ) { mesh.numPoints() = mesh.storedPoints(); sw.create ( "FIXED_POINTS_COUNTER", true ); } } //----------------------------------------------------- // FINAL CHECKS //----------------------------------------------------- if ( verbose ) out << " ******** COUNTERS CONTENT **********************************" << std::endl << " Num Volumes : " << mesh.numVolumes() << std::endl << " Num Vertices : " << mesh.numVertices() << std::endl << " Num B. Vertices: " << mesh.numBVertices() << std::endl << " Num Points : " << mesh.numPoints() << std::endl << " Num B. Points : " << mesh.numBPoints() << std::endl << " Num Edges : " << mesh.numEdges() << std::endl << " Num B. Edges : " << mesh.numBEdges() << std::endl << " Num Faces : " << mesh.numFaces() << std::endl << " Num B. Faces : " << mesh.numBFaces() << std::endl << " ******** END COUNTERS **********************************" << std::endl; bool eulok1 = ( 2 * mesh.numFaces() - mesh.numLocalFaces() * mesh.numVolumes() - mesh.numBFaces() ) == 0; bool eulok2 ( true ); if ( RegionMesh::elementShape_Type::S_shape == TETRA ) { if ( verbose ) { out << std::endl << "Checking Euler formulae: "; } eulok2 = ( mesh.numEdges() - mesh.numVolumes() - mesh.numVertices() - ( 3 * mesh.numBFaces() - 2 * mesh.numBVertices() ) / 4 ) == 0; } if ( ! ( eulok1 && eulok2 ) ) { if ( verbose ) err << "WARNING: The following Euler formula(s) are not satisfied" << std::endl; sw.create ( "NOT_EULER_OK" ); } else { if ( verbose ) { out << std::endl << " ok." << std::endl; } } if ( !eulok1 ) { if ( verbose ) err << " 2*nFaces = nFacesPerVolume*nVolumes + nBoundaryFaces" << std::endl << " 2*" << mesh.numFaces() << " != " << mesh.numLocalFaces() << " * " << mesh.numVolumes() << " + " << mesh.numBFaces() << std::endl; } if ( !eulok2 ) { if ( verbose ) err << " nEdges = nVolumes + nVertices + (3*nBoundaryFaces - 2*nBoundaryVertices)/4" << std::endl << " " << mesh.numEdges() << " != " << mesh.numVolumes() << " + " << mesh.numVertices() << " + (3*" << mesh.numBFaces() << " - 2*" << mesh.numBVertices() << ")/4" << std::endl; } mesh.setLinkSwitch ( "HAS_BEEN_CHECKED" ); return true; }