37 #ifndef __MESH_UTILITIES__ 38 #define __MESH_UTILITIES__ 40 #include <lifev/core/LifeV.hpp> 42 #include <lifev/core/mesh/MeshUtility.hpp> 43 #include <lifev/core/fem/GeometricMap.hpp> 44 #include <lifev/core/fem/CurrentFE.hpp> 45 #include <lifev/core/fem/CurrentFEManifold.hpp> 110 template <
typename RegionMesh>
112 std::vector<
bool>& elSign,
118 elSign.reserve ( mesh.numVolumes() );
119 typedef typename RegionMesh::elementShape_Type GeoShape;
121 switch ( GeoShape::S_shape )
125 CurrentFE fe ( feTetraP1, geoLinearTetra, quadRuleTetra1pt );
126 for (
ID i = 0; i < mesh.numVolumes(); i++ )
128 fe.updateJac ( mesh.volume ( i ) );
129 lmeas = fe.measure();
131 elSign.push_back ( lmeas > 0.0 );
137 CurrentFE fe ( feHexaQ1, geoBilinearHexa, quadRuleHexa1pt );
138 for (
ID i = 0; i < mesh.numVolumes(); i++ )
140 fe.updateJac ( mesh.volume ( i ) );
141 lmeas = fe.measure();
143 elSign.push_back ( lmeas > 0.0 );
153 if ( std::find ( elSign.begin(), elSign.end(),
false ) != elSign.end() )
174 template <
typename RegionMesh>
176 const std::vector<
bool>& elSign,
180 for (
ID i = 0; i < mesh.numVolumes(); i++ )
184 mesh.volume (i).reversePoints();
201 template <
typename RegionMesh>
204 std::ostream& err = std::cerr )
212 typedef typename RegionMesh::facetShape_Type GeoBShape;
213 typedef std::shared_ptr<CurrentFEManifold> current_fe_type;
215 current_fe_type bdfe;
217 switch ( GeoBShape::S_shape )
220 bdfe = current_fe_type (
new CurrentFEManifold ( feTriaP1, geoLinearTria,
222 for (
ID i = 0; i < mesh.numBFaces(); i++ )
224 bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
225 vols[ 0 ] += bdfe->normalIntegral ( getx );
226 vols[ 1 ] += bdfe->normalIntegral ( gety );
227 vols[ 2 ] += bdfe->normalIntegral ( getz );
231 bdfe = current_fe_type (
new CurrentFEManifold ( feQuadQ1, geoBilinearQuad,
233 for (
ID i = 0; i < mesh.numBFaces(); i++ )
235 bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
236 vols[ 0 ] += bdfe->normalIntegral ( getx );
237 vols[ 1 ] += bdfe->normalIntegral ( gety );
238 vols[ 2 ] += bdfe->normalIntegral ( getz );
242 err <<
"Only tria and quad surface elements may be checked for volume orientation at the moment" << std::endl;
243 ASSERT0 (
false,
"ABORT CONDITION OCCURRED" );
251 template <
typename RegionMesh>
253 std::ostream& err = std::cerr )
255 typedef std::shared_ptr<CurrentFEManifold> current_fe_type;
256 current_fe_type bdfe;
261 switch ( RegionMesh::facetShape_Type::S_shape )
264 bdfe = current_fe_type (
new CurrentFEManifold ( feTriaP1, geoLinearTria,
266 for (
ID i = 0; i < mesh.numBFaces(); i++ )
268 bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
269 test += bdfe->normalIntegral ( ones );
273 bdfe = current_fe_type (
new CurrentFEManifold ( feQuadQ1, geoBilinearQuad,
275 for (
ID i = 0; i < mesh.numBFaces(); i++ )
277 bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
278 test += bdfe->normalIntegral ( ones );
284 err <<
"Only tria and quad surface elements may be checked for volume orientation at the moment" << std::endl;
285 ASSERT0 (
false,
"ABORT CONDITION OCCURRED" );
315 template <
typename RegionMesh>
319 bool verbose =
false,
320 std::ostream& out = std::cerr,
321 std::ostream& err = std::cerr,
322 std::ostream& clog = std::clog )
324 verbose = verbose && ( mesh.comm()->MyPID() == 0 );
325 typedef typename RegionMesh::point_Type point_Type;
327 if ( mesh.storedPoints() == 0 )
329 err <<
"FATAL: mesh does not store points: I cannot do anything" 338 out <<
" Check point marker ids" << std::endl;
340 if ( !
MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
344 err <<
"WARNING: Not all points have marker id set" << std::endl;
356 if ( mesh.storedVolumes() == 0 )
358 if (verbose) err <<
"FATAL: mesh does not store volumes: I cannot do anything" 370 err <<
"ERROR: volume ids were wrongly set" << std::endl;
371 err <<
"FIXED" << std::endl;
385 out <<
" Check volum marker ids" << std::endl;
387 if ( !
MeshUtility::checkIsMarkerSet ( mesh.volumeList ) )
391 err <<
"WARNING: Not all volumes have marker flag set" << std::endl;
400 out <<
"Fixing volume marker ids" << std::endl;
402 for (
typename RegionMesh::volumes_Type::iterator iv = mesh.volumeList.begin();
403 iv != mesh.volumeList.end(); ++iv )
405 if ( iv->isMarkerUnset() )
407 iv->setMarkerID ( mesh.markerID() );
413 if ( mesh.numElements() < mesh.storedVolumes() )
416 err <<
"WARNING: Mesh Volumes must be at least " 417 << mesh.storedVolumes() << std::endl;
420 mesh.setNumVolumes ( mesh.storedVolumes() );
430 std::shared_ptr<std::vector<
bool> > elSign (
new std::vector<
bool> );
432 Real meshMeasure = checkVolumes ( mesh, *elSign, sw );
435 if ( sw.test (
"SKIP_ORIENTATION_TEST" ) )
439 clog <<
"W: ELEMENT ORIENTATION NOT IMPLEMENTED YET FOR THIS TYPE OF ELEMENTS, SKIP" << std::endl;
440 err <<
"W: ELEMENT ORIENTATION NOT IMPLEMENTED YET FOR THIS TYPE OF ELEMENTS, SKIP" << std::endl;
443 else if ( sw.test (
"HAS_NEGATIVE_VOLUMES" ) )
447 out <<
"Checking volume orientation" << std::endl;
449 positive = count ( elSign->begin(), elSign->end(),
true );
450 if ( verbose ) clog << positive <<
"W: positive elements out of" 451 << mesh.storedVolumes() << std::endl;
456 clog <<
"Fixing negative elements" << std::endl;
458 fixVolumes ( mesh, *elSign, sw );
461 if ( sw.test (
"ABORT_CONDITION" ) )
463 if (verbose) err <<
"ABORT: Cannot fix volumes, this element is not supported" 469 sw.unset (
"HAS_NEGATIVE_VOLUMES" );
470 meshMeasure = checkVolumes ( mesh, *elSign, sw );
471 if ( sw.test (
"HAS_NEGATIVE_VOLUMES" ) )
477 err <<
"ABORT: Cannot fix volumes: something wrong with this mesh" << std::endl;
479 sw.create (
"ABORT_CONDITION",
true );
486 if ( verbose ) clog <<
"Volume enclosed by the mesh= " << meshMeasure << std::endl
487 <<
"(Computed by integrating mesh elements measures)" << std::endl
488 <<
"(Using 1 point Quadrature rule)" << std::endl;
494 std::shared_ptr<MeshUtility::temporaryFaceContainer_Type> bfaces (
495 new MeshUtility::temporaryFaceContainer_Type );
496 UInt numInternalFaces, numFaces;
500 out <<
"Finding boundary faces from mesh topology" << std::endl;
503 UInt bFacesFound = MeshUtility::findBoundaryFaces ( mesh, *bfaces, numInternalFaces );
505 numFaces = bFacesFound + numInternalFaces;
507 MeshUtility::EnquireBFace<RegionMesh> enquireBFace (*bfaces );
509 UInt meshNumBoundaryFaces ( mesh.numBFaces() + mesh.faceList.countElementsWithFlag ( EntityFlags::SUBDOMAIN_INTERFACE, &Flag::testOneSet ) );
511 if ( mesh.storedFaces() == 0 ||
512 meshNumBoundaryFaces > mesh.storedFaces() ||
513 bFacesFound > mesh.storedFaces() || bFacesFound > meshNumBoundaryFaces )
518 err <<
"ERROR: Not all boundary faces stored" << std::endl;
519 err <<
"Found " << bFacesFound <<
" stored " << mesh.storedFaces() <<
520 "B faces declared in mesh " << meshNumBoundaryFaces << std::endl;
524 sw.create (
"BUILD_BFACES",
true );
527 out <<
"Building boundary faces from topology data" << std::endl;
529 MeshUtility::buildFaces ( mesh, clog, err, bFacesFound, numInternalFaces,
530 true,
false,
false, bfaces.get() );
534 err <<
"After buildFaces" << std::endl;
535 err <<
"Found " << bFacesFound <<
" stored " << mesh.storedFaces()
536 <<
"B faces declared in mesh " << meshNumBoundaryFaces << std::endl;
541 if ( mesh.storedFaces() == 0 )
545 err <<
"ABORT CONDITION: cannot find boundary faces" << std::endl;
547 sw.create (
"NOT_HAS_FACES",
true );
548 sw.create (
"ABORT_CONDITION",
true );
560 out <<
"Rearranging faces so that boundary faces are first" << std::endl;
562 MeshUtility::rearrangeFaces ( mesh, clog, err, sw, numFaces, bFacesFound,
563 verbose, bfaces.get() );
565 if ( meshNumBoundaryFaces != bFacesFound)
569 err <<
" ERROR: Number of B faces does not correspond to real one" << std::endl;
575 err <<
"FIXED Number of B faces has been fixed to:" << bFacesFound << std::endl;
577 mesh.setNumBFaces ( bFacesFound);
581 if ( !MeshUtility::checkId ( mesh.faceList ) )
585 err <<
"ERROR: face ids were wrongly set" << std::endl;
586 err <<
"FIXED" << std::endl;
590 sw.create (
"FIXED_FACES_ID",
true );
591 MeshUtility::fixId ( mesh.faceList );
601 out <<
"Make sure that adjacent elements of boundary faces are correct" << std::endl;
603 MeshUtility::fixBoundaryFaces ( mesh, clog, err, sw, numFaces, bFacesFound,
604 false, verbose, bfaces.get() );
609 if ( mesh.numBFaces() == 0 )
613 err <<
" MeshBFaces counter is unset" << std::endl;
617 mesh.setNumBFaces ( mesh.storedFaces() );
618 sw.create (
"FIXED_BFACE_COUNTER",
true );
619 mesh.setLinkSwitch (
"HAS_BOUNDARY_FACETS" );
624 if ( !MeshUtility::checkIsMarkerSet ( mesh.faceList ) )
628 out <<
"Fix markers id for faces" << std::endl;
632 err <<
"WARNING: Not all faces have marker flag set" << std::endl;
634 sw.create (
"FACE_MARKER_UNSET",
true );
637 MeshUtility::setBoundaryFacesMarker ( mesh, clog, err, verbose );
639 if ( fix && MeshUtility::checkIsMarkerSet ( mesh.faceList ) )
641 sw.create (
"FACE_MARKER_UNSET",
false );
642 sw.create (
"FACE_MARKER_FIXED",
true );
648 if ( mesh.numFaces() != bFacesFound + numInternalFaces )
652 err <<
"WARNING Number of faces incorrectly set" << std::endl;
653 err <<
" It was " << mesh.numFaces() << std::endl;
654 err <<
" It should be " << bFacesFound + numInternalFaces
661 err <<
" Fixing" << std::endl;
663 mesh.setNumFaces ( bFacesFound + numInternalFaces );
664 sw.create (
"FIXED_FACE_COUNTER",
true );
668 if ( fix && mesh.storedFaces() == bFacesFound + numInternalFaces)
670 mesh.setLinkSwitch (
"HAS_ALL_FACETS" );
676 out <<
" Boundary faces found :" << bFacesFound << std::endl;
677 out <<
" Num Faces Stored stored :" << mesh.storedFaces() << std::endl;
678 out <<
" Num faces in mesh :" << mesh.numFaces() << std::endl;
679 out <<
" Boundary faces counter gives:" << mesh.numBFaces() << std::endl;
686 std::shared_ptr<MeshUtility::temporaryEdgeContainer_Type> bedges (
687 new MeshUtility::temporaryEdgeContainer_Type );
689 UInt bEdgesFound = MeshUtility::findBoundaryEdges ( mesh, *bedges );
690 MeshUtility::EnquireBEdge<RegionMesh> enquireBEdge (*bedges );
694 MeshUtility::temporaryEdgeContainer_Type iedges;
696 if ( mesh.storedEdges() == 0 ||
697 mesh.numBEdges() > mesh.storedEdges() ||
698 bEdgesFound > mesh.storedEdges() )
702 err <<
"WARNING: mesh does not store (all) boundary edges" << std::endl;
704 sw.create (
"NOT_HAS_EDGES",
true );
709 out <<
"Build boundary edges" << std::endl;
711 MeshUtility::buildEdges ( mesh, clog, err, bEdgesFound, intedge,
true,
false,
712 false, bedges.get() );
714 Ned = bEdgesFound + intedge;
717 sw.create (
"BUILD_BEDGES",
true );
728 if ( mesh.numBEdges() != bEdgesFound)
732 err <<
" ERROR: Number of BEdges does not correspond to real one" << std::endl;
738 err <<
"FIXED Number of BEdges has been fixed to:" << bEdgesFound << std::endl;
740 mesh.setNumBEdges ( bEdgesFound);
748 out <<
"Reorder edges so that boundary are first" << std::endl;
750 mesh.edgeList.reorderAccordingToFlag (EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet);
752 sw.create (
"FIXED_BEDGES_FIRST" );
754 if ( !MeshUtility::checkId ( mesh.edgeList ) )
758 err <<
"ERROR: edge ids were wrongly set" << std::endl;
764 err <<
"FIXED" << std::endl;
766 sw.create (
"FIXED_EDGES_ID",
true );
767 MeshUtility::fixId ( mesh.edgeList );
772 if ( !MeshUtility::checkIsMarkerSet ( mesh.edgeList ) )
776 err <<
"WARNING: Not all edges have marker flag set" << std::endl;
778 sw.create (
"EDGE_MARKER_UNSET",
true );
783 out <<
"Fix boundary edges marker" << std::endl;
785 MeshUtility::setBoundaryEdgesMarker ( mesh, clog, err, verbose );
787 if ( fix && MeshUtility::checkIsMarkerSet ( mesh.edgeList ) )
789 sw.unset (
"EDGE_MARKER_UNSET" );
790 sw.create (
"EDGE_MARKER_FIXED",
true );
795 out <<
"Computing number of internal edges";
799 Ned = bEdgesFound + MeshUtility::findInternalEdges ( mesh, *bedges, iedges );
803 MeshUtility::temporaryEdgeContainer_Type tmp;
806 if ( mesh.numBEdges() != bEdgesFound )
808 if ( verbose ) err <<
"WARNING: number of found boundary edges:" << bEdgesFound
810 <<
" does not match that declared in mesh, i.e. " 811 << mesh.numBEdges() << std::endl;
812 if ( mesh.numBEdges() == 0 )
818 err <<
"FIXING" << std::endl;
820 sw.create (
"FIXED_BEDGES_COUNTER",
true );
821 mesh.setNumBEdges ( bEdgesFound );
826 if ( Ned != mesh.numEdges() )
830 if ( verbose ) err <<
"WARNING: Counter of number of edges badly set: Should be (actual number)" << Ned << std::endl
831 <<
"It is instead equal to " << mesh.numEdges() << std::endl;
832 err <<
" **FIXED" << std::endl;
833 mesh.setNumEdges ( Ned );
837 UInt counte = MeshUtility::testDomainTopology ( mesh, nbed );
842 out <<
"**DOMAIN SURFACE IS (TOPOLOGICALLY) CLOSED" << std::endl;
847 sw.create (
"DOMAIN_NOT_CLOSED",
true );
848 if ( verbose ) err <<
"WARNING: DOMAIN APPEARS TO HAVE AN OPEN BOUNDARY (TOPOLOGY CHECK)" << std::endl
849 <<
"Number of inconsistent edges:" << counte << std::endl;
860 out <<
"Checking vertexes" << std::endl;
862 UInt numVerticesFound = mesh.pointList.countElementsWithFlag (EntityFlags::VERTEX, &Flag::testOneSet);
863 if (numVerticesFound != mesh.numVertices() )
867 err <<
"warning: The number of Points with vertex flag on does not coincide with the declared one." << std::endl;
873 err <<
"It will be fixed now" << std::endl;
876 for (UInt i = 0; i < mesh.numPoints(); ++i)
878 mesh.point (i).unSetFlag (EntityFlags::VERTEX);
881 for (UInt i = 0; i < mesh.numElements(); ++i)
882 for (UInt j = 0; j < mesh.numLocalVertices(); ++j)
884 ID k = mesh.element (i).point (j).localId();
885 mesh.pointList (k).setFlag (EntityFlags::VERTEX);
887 numVerticesFound = mesh.pointList.countElementsWithFlag (
888 EntityFlags::VERTEX, &Flag::testOneSet);
889 mesh.setNumVertices (numVerticesFound);
890 UInt numBVerticesFound = mesh.pointList.countElementsWithFlag (
891 EntityFlags::VERTEX | EntityFlags::PHYSICAL_BOUNDARY, &Flag::testAllSet);
892 mesh.setNumBVertices (numBVerticesFound);
893 sw.create (
"FIXED_VERTICES_COUNTER",
true );
904 out <<
"Fix boundary points using boundary faces info" << std::endl;
906 MeshUtility::fixBoundaryPoints (mesh, clog, err, verbose);
909 MeshUtility::EnquireBPoint<RegionMesh> enquirebpoint ( mesh );
911 UInt foundBPoints = mesh.pointList.countElementsWithFlag (EntityFlags::PHYSICAL_BOUNDARY,
915 out <<
"B Points Found " << foundBPoints << std::endl;
917 if ( foundBPoints == 0 || foundBPoints < mesh.storedBPoints() )
921 err <<
"ERROR Bpoints indicator not correctly set" << std::endl;
928 sw.create (
"FIXED_BOUNDARY_POINTS",
true );
935 out <<
"Chsck point marker Ids" << std::endl;
937 if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
941 err <<
"Points MARKER id incorrectly set" << std::endl;
948 err <<
" Fixing Points Marker ID" << std::endl <<
"If unset the boundary will inherit the strongest among faces" << std::endl;
952 err <<
" The internal will be set to the domain flag" << std::endl;
954 MeshUtility::setBoundaryPointsMarker ( mesh, clog, err,
false );
956 if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
959 bool boundaryIsOk (
true);
960 std::vector<point_Type
const*>
961 listOfPt = mesh.pointList.extractElementsWithFlag (
962 EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet);
963 for (
typename std::vector<point_Type
const*>::const_iterator
964 it = listOfPt.begin();
968 boundaryIsOk = boundaryIsOk | (*it)->isMarkerSet();
970 std::vector<point_Type
const*>().swap (listOfPt);
973 clog <<
" Marker ID on boundary points is fine. Internal points may have marker unset" << std::endl;
977 err <<
"Cannot Fix Points MARKER" << std::endl;
979 if ( verbose && boundaryIsOk )
981 err <<
"But boundary points are fine" << std::endl;
983 sw.create (
"POINT_MARKER_UNSET",
true );
989 err <<
"FIXED" << std::endl;
991 sw.create (
"FIXED_POINT_MARKER",
true );
997 if ( mesh.storedBPoints() == 0 )
1001 err <<
"WARNING B. Points COUNTER incorrectly set" << std::endl;
1005 MeshUtility::setBoundaryPointsCounters ( mesh ) ;
1008 err <<
" FIXED" << std::endl;
1010 sw.create (
"FIXED_BPOINTS_COUNTER",
true );
1014 if ( mesh.numPoints() == 0 )
1018 err <<
"WARNING Points Counter unset" << std::endl;
1022 mesh.numPoints() = mesh.storedPoints();
1023 sw.create (
"FIXED_POINTS_COUNTER",
true );
1030 if ( verbose ) out <<
" ******** COUNTERS CONTENT **********************************" << std::endl
1032 <<
" Num Volumes : " << mesh.numVolumes() << std::endl
1033 <<
" Num Vertices : " << mesh.numVertices() << std::endl
1034 <<
" Num B. Vertices: " << mesh.numBVertices() << std::endl
1035 <<
" Num Points : " << mesh.numPoints() << std::endl
1036 <<
" Num B. Points : " << mesh.numBPoints() << std::endl
1037 <<
" Num Edges : " << mesh.numEdges() << std::endl
1038 <<
" Num B. Edges : " << mesh.numBEdges() << std::endl
1039 <<
" Num Faces : " << mesh.numFaces() << std::endl
1040 <<
" Num B. Faces : " << mesh.numBFaces() << std::endl
1041 <<
" ******** END COUNTERS **********************************" 1044 bool eulok1 = ( 2 * mesh.numFaces() -
1045 mesh.numLocalFaces() * mesh.numVolumes() -
1046 mesh.numBFaces() ) == 0;
1048 bool eulok2 (
true );
1050 if ( RegionMesh::elementShape_Type::S_shape == TETRA )
1054 out << std::endl <<
"Checking Euler formulae: ";
1056 eulok2 = ( mesh.numEdges() -
1058 mesh.numVertices() -
1059 ( 3 * mesh.numBFaces() -
1060 2 * mesh.numBVertices() ) / 4 ) == 0;
1063 if ( ! ( eulok1 && eulok2 ) )
1065 if ( verbose ) err <<
"WARNING: The following Euler formula(s) are not satisfied" 1067 sw.create (
"NOT_EULER_OK" );
1073 out << std::endl <<
" ok." << std::endl;
1079 if ( verbose ) err <<
" 2*nFaces = nFacesPerVolume*nVolumes + nBoundaryFaces" 1081 <<
" 2*" << mesh.numFaces() <<
" != " << mesh.numLocalFaces()
1082 <<
" * " << mesh.numVolumes() <<
" + " << mesh.numBFaces()
1088 if ( verbose ) err <<
" nEdges = nVolumes + nVertices + (3*nBoundaryFaces - 2*nBoundaryVertices)/4" << std::endl
1089 <<
" " << mesh.numEdges() <<
" != " << mesh.numVolumes() <<
" + " 1090 << mesh.numVertices() <<
" + (3*" << mesh.numBFaces() <<
" - 2*" 1091 << mesh.numBVertices() <<
")/4" << std::endl;
1094 mesh.setLinkSwitch (
"HAS_BEEN_CHECKED" );
I use standard constructor/destructors.
GetCoordComponent(Int i)
Constructor taking the component.
void create(const char *a, bool status=false)
This functor is used to do some geometry checks.
Real testClosedDomain(RegionMesh const &mesh, std::ostream &err=std::cerr)
Tests if the surface of the mesh is closed by computing surface integrals.
void getVolumeFromFaces(RegionMesh const &mesh, Real vols[3], std::ostream &err=std::cerr)
Computes volume enclosed by boundary faces.
double Real
Generic real data.
CurrentFE - A primordial class for the assembly of the local matrices/vectors retaining the values on...
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)
This function performs a lot of checks.
Real checkVolumes(RegionMesh const &mesh, std::vector< bool > &elSign, Switch &sw)
Report 3D element orientation.
void fixVolumes(RegionMesh &mesh, const std::vector< bool > &elSign, Switch &sw)
Fixes negative volume elements.