LifeV
MeshChecks.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief Base utilities operating on meshes
30 
31  @contributor Simone Deparis <simone.deparis@epfl.ch>
32  @maintainer Simone Deparis <simone.deparis@epfl.ch>
33 
34  This file contains a set of base utilities used to test mesh entities or
35  operate on them
36  */
37 #ifndef __MESH_UTILITIES__
38 #define __MESH_UTILITIES__
39 
40 #include <lifev/core/LifeV.hpp>
41 
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>
46 
47 //! \file mesh_util.h
48 //! \file mesh_util.h
49 /*!
50  This file contains a set of functions to be used to test a 3D mesh and fix
51  some possible problems. Some methods are general (2D and 3D meshes), some are
52  specific to 3D meshes.
53 
54  They sometimes require in input a Switch paramenter sw and ostreams references.
55  The switch values are
56 <UL>
57 <LI>"ABORT_CONDITION" "SKIPPED_ORIENTATION_TEST"</LI>
58 <LI>"HAS_NEGATIVE_VOLUMES" "BFACE_STORED_MISMATCH"</LI>
59 <LI>"BELEMENT_COUNTER_UNSET" "BFACE_COUNTER_MISMATCH"</LI>
60 <LI>"BFACE_MISSING" "FIXED_MAX_NUM_FACES"</LI>
61 <LI>"FIXED_FACE_COUNTER" "NUM_FACES_MISMATCH"</LI>
62 <LI>"FIXED_MAX_NUM_EDGES" "FIXED_EDGES"</LI>
63 <LI>"NOT_HAS_POINTS" "FIXED_POINTS_ID"</LI>
64 <LI>"POINTS_MARKER_UNSET" "NOT_HAS_VOLUMES"</LI>
65 <LI>"FIXED_VOLUMES_ID" "VOLUMES_MARKER_UNSET"</LI>
66 <LI>"FIXED_VOLUME_COUNTER" "BUILD_BFACES"</LI>
67 <LI>"FIXED_BFACES_FIRST" "FIXED_FACES_ID"</LI>
68 <LI>"NOT_HAS_FACES" "FIXED_BFACE_COUNTER"</LI>
69 <LI>"FACE_MARKER_UNSET" "FACE_MARKER_FIXED"</LI>
70 <LI>"FIXED_FACE_COUNTER" "NOT_HAS_EDGES"</LI>
71 <LI>"BUILD_BEDGES" "FIXED_BEDGES_FIRST" </LI>
72 <LI>"FIXED_EDGES_ID" "EDGE_MARKER_UNSET"</LI>
73 <LI>"EDGE_MARKER_FIXED" "FIXED_BEDGES_COUNTER"</LI>
74 <LI>"DOMAIN_NOT_CLOSED" "FIXED_BOUNDARY_POINTS"</LI>
75 <LI>"POINT_MARKER_UNSET" "FIXED_POINT_MARKER"</LI>
76 <LI>"FIXED_BPOINTS_COUNTER" "NOT_EULER_OK"</LI>
77 </UL>
78 
79 \pre All functions contained in this file require as precondition a mesh
80 with the points and volumes connectivity set. Some functions have also
81 other preconditions, which will be then specified in the function
82 documentation.
83 */
84 namespace LifeV
85 {
86 /*
87 *****************************************************************************
88  GEOMETRY TESTS
89 *****************************************************************************
90 */
91 //! \brief Report 3D element orientation
92 /*! It uses a linear representation of the Tetra/Hexa: it is only a
93  orientation check. The orientation is considered positive if it
94  obeys the right-hand rule (right-hand orientation).
95 
96  \param mesh A region mesh of 3D elements
97 
98  \param elSign A vector of bool: true means positive orientation.
99 
100  \param sw The switch used to communicate test results. This function may
101  set the conditions
102  <TT>HAS_NEGATIVE_VOLUMES,SKIP_ORIENTATION_TEST</TT>
103 
104  The first reports that some mesh elements have negative volume, the
105  second that the test has been skipped because has not yet beem
106  implemented for the element under consideration.
107 
108  \return It returns the mesh computed volume.
109 */
110 template <typename RegionMesh>
111 Real checkVolumes ( RegionMesh const& mesh,
112  std::vector<bool>& elSign,
113  Switch& sw )
114 {
115  Real meas = 0.0;
116  Real lmeas = 0.0;
117  elSign.clear();
118  elSign.reserve ( mesh.numVolumes() );
119  typedef typename RegionMesh::elementShape_Type GeoShape;
120 
121  switch ( GeoShape::S_shape )
122  {
123  case TETRA:
124  {
125  CurrentFE fe ( feTetraP1, geoLinearTetra, quadRuleTetra1pt );
126  for ( ID i = 0; i < mesh.numVolumes(); i++ )
127  {
128  fe.updateJac ( mesh.volume ( i ) );
129  lmeas = fe.measure();
130  meas += lmeas;
131  elSign.push_back ( lmeas > 0.0 );
132  }
133  }
134  break;
135  case HEXA:
136  {
137  CurrentFE fe ( feHexaQ1, geoBilinearHexa, quadRuleHexa1pt );
138  for ( ID i = 0; i < mesh.numVolumes(); i++ )
139  {
140  fe.updateJac ( mesh.volume ( i ) );
141  lmeas = fe.measure();
142  meas += lmeas;
143  elSign.push_back ( lmeas > 0.0 );
144  }
145  }
146  break;
147  default:
148  sw.create ( "SKIP_ORIENTATION_TEST", true );
149 
150  return 0;
151  }
152 
153  if ( std::find ( elSign.begin(), elSign.end(), false ) != elSign.end() )
154  {
155  sw.create ( "HAS_NEGATIVE_VOLUMES", true );
156  }
157 
158  return meas;
159 }
160 
161 /*!
162  \brief Fixes negative volume elements.
163 
164  Given a std::vector<bool> indicating negative elements, it inverts those that
165  have been found negative.
166 
167  \param mesh A 3D mesh. It will be modified.
168 
169  \param elSign a vector of bools. The value false correspond to the elements that have to be swapped. It is created by
170  checkVolumes().
171 
172  \post A mesh with all volumes with positive oreintation.
173 */
174 template <typename RegionMesh>
175 void fixVolumes ( RegionMesh& mesh,
176  const std::vector<bool>& elSign,
177  Switch& sw )
178 {
179 
180  for ( ID i = 0; i < mesh.numVolumes(); i++ )
181  {
182  if ( ! elSign[ i ] )
183  {
184  mesh.volume (i).reversePoints();
185  }
186  }
187  sw.create ("HAS_VOLUMES", true);
188 }
189 //!\brief Computes volume enclosed by boundary faces
190 /*!
191  It computes, for $i=0,1,2$, the integral \f$\int_{\partial \Omega} x_i n_i
192  d\gamma \f$, \f$n_i\f$ being the i-th component of the boundary normal. If
193  the domain boundary is properly discretised they should all return (within
194  discretisation and truncation errors) the quantity \f$\vert\Omega\vert\f$.
195 
196  \warning Not to be used for accurate computations (it always adopts
197  linear or bilinear elements, with a simple integration rule)
198  \param mesh A 3D mesh
199  \param vols returns 3 Real corresponding to the 3 integrals
200 */
201 template <typename RegionMesh>
202 void getVolumeFromFaces ( RegionMesh const& mesh,
203  Real vols[ 3 ],
204  std::ostream& err = std::cerr )
205 {
209  vols[ 0 ] = 0.0;
210  vols[ 1 ] = 0.0;
211  vols[ 2 ] = 0.0;
212  typedef typename RegionMesh::facetShape_Type GeoBShape;
213  typedef std::shared_ptr<CurrentFEManifold> current_fe_type;
214 
215  current_fe_type bdfe;
216 
217  switch ( GeoBShape::S_shape )
218  {
219  case TRIANGLE:
220  bdfe = current_fe_type ( new CurrentFEManifold ( feTriaP1, geoLinearTria,
221  quadRuleTria1pt ) );
222  for ( ID i = 0; i < mesh.numBFaces(); i++ )
223  {
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 );
228  }
229  break;
230  case QUAD:
231  bdfe = current_fe_type ( new CurrentFEManifold ( feQuadQ1, geoBilinearQuad,
232  quadRuleQuad1pt ) );
233  for ( ID i = 0; i < mesh.numBFaces(); i++ )
234  {
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 );
239  }
240  break;
241  default:
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" );
244  }
245 }
246 
247 //! Tests if the surface of the mesh is closed by computing surface integrals.
248 /*! It computes \f$\sum_{i=0}^2\int_{\partial \Omega} n_i d\gamma\f$.
249  The value returned should be very proximal to zero
250  */
251 template <typename RegionMesh>
252 Real testClosedDomain ( RegionMesh const& mesh,
253  std::ostream& err = std::cerr )
254 {
255  typedef std::shared_ptr<CurrentFEManifold> current_fe_type;
256  current_fe_type bdfe;
257 
258  MeshUtility::GetOnes ones;
259  Real test ( 0.0 );
260 
261  switch ( RegionMesh::facetShape_Type::S_shape )
262  {
263  case TRIANGLE:
264  bdfe = current_fe_type ( new CurrentFEManifold ( feTriaP1, geoLinearTria,
265  quadRuleTria1pt ) );
266  for ( ID i = 0; i < mesh.numBFaces(); i++ )
267  {
268  bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
269  test += bdfe->normalIntegral ( ones );
270  }
271  break;
272  case QUAD:
273  bdfe = current_fe_type ( new CurrentFEManifold ( feQuadQ1, geoBilinearQuad,
274  quadRuleQuad1pt ) );
275  for ( ID i = 0; i < mesh.numBFaces(); i++ )
276  {
277  bdfe->update ( mesh.face ( i ), UPDATE_W_ROOT_DET_METRIC | UPDATE_NORMALS | UPDATE_QUAD_NODES );
278  test += bdfe->normalIntegral ( ones );
279  }
280 
281  break;
282 
283  default:
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" );
286  }
287 
288  return test;
289 
290 }
291 
292 /*
293 *****************************************************************************
294  UTILITIES FOR GLOBAL CHECKINGS
295 *****************************************************************************
296 */
297 
298 //! This function performs a lot of checks.
299 
300 /*!
301  The name is inappropriate since the tests that are performed are not just on
302  the topological structure of the mesh. The output is directed to three
303  output streams:
304  <ul>
305  <li> out-> usually standard output: important informative messages
306  <li> err-> usually standard error: error messages
307  <li> clog-> usually a file stream: informative messages which may be rather verbose.
308  </ul>
309  Furthermore, ths Switch sw (see switch.h) will return a set of
310  keywords useful for other possible actions. If fix=true, this routines
311  performes the steps needed to get an acceptable mesh, otherwise the input
312  mesh is not modified .
313 */
314 
315 template <typename RegionMesh>
316 bool checkMesh3D ( RegionMesh& mesh,
317  Switch& sw,
318  bool fix = true,
319  bool verbose = false,
320  std::ostream& out = std::cerr,
321  std::ostream& err = std::cerr,
322  std::ostream& clog = std::clog )
323 {
324  verbose = verbose && ( mesh.comm()->MyPID() == 0 );
325  typedef typename RegionMesh::point_Type point_Type;
326 
327  if ( mesh.storedPoints() == 0 )
328  {
329  err << "FATAL: mesh does not store points: I cannot do anything"
330  << std::endl;
331  sw.create ( "ABORT_CONDITION", true );
332  sw.create ( "NOT_HAS_POINTS", true );
333  return false;
334  }
335 
336  if (verbose)
337  {
338  out << " Check point marker ids" << std::endl;
339  }
340  if ( !MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
341  {
342  if (verbose)
343  {
344  err << "WARNING: Not all points have marker id set" << std::endl;
345  }
346 
347  sw.create ( "POINTS_MARKER_UNSET", true );
348  }
349 
350 
351  //-------------------------------------------------------------------------
352  // VOLUMES
353  //-------------------------------------------------------------------------
354 
355 
356  if ( mesh.storedVolumes() == 0 )
357  {
358  if (verbose) err << "FATAL: mesh does not store volumes: I cannot do anything"
359  << std::endl;
360  sw.create ( "ABORT_CONDITION", true );
361  sw.create ( "NOT_HAS_VOLUMES", true );
362  return false;
363  }
364 
365 
366  if ( !MeshUtility::checkId ( mesh.volumeList ) )
367  {
368  if (verbose)
369  {
370  err << "ERROR: volume ids were wrongly set" << std::endl;
371  err << "FIXED" << std::endl;
372  }
373  if ( fix )
374  {
375  sw.create ( "FIXED_VOLUMES_ID", true );
376  }
377  if ( fix )
378  {
379  MeshUtility::fixId ( mesh.volumeList );
380  }
381  }
382 
383  if (verbose)
384  {
385  out << " Check volum marker ids" << std::endl;
386  }
387  if ( !MeshUtility::checkIsMarkerSet ( mesh.volumeList ) )
388  {
389  if (verbose)
390  {
391  err << "WARNING: Not all volumes have marker flag set" << std::endl;
392  }
393 
394  sw.create ( "VOLUMES_MARKER_UNSET", true );
395 
396  if ( fix )
397  {
398  if (verbose)
399  {
400  out << "Fixing volume marker ids" << std::endl;
401  }
402  for ( typename RegionMesh::volumes_Type::iterator iv = mesh.volumeList.begin();
403  iv != mesh.volumeList.end(); ++iv )
404  {
405  if ( iv->isMarkerUnset() )
406  {
407  iv->setMarkerID ( mesh.markerID() );
408  }
409  }
410  }
411  }
412 
413  if ( mesh.numElements() < mesh.storedVolumes() )
414  {
415  if (verbose)
416  err << "WARNING: Mesh Volumes must be at least "
417  << mesh.storedVolumes() << std::endl;
418  if ( fix )
419  {
420  mesh.setNumVolumes ( mesh.storedVolumes() );
421  }
422  if ( fix )
423  {
424  sw.create ( "FIXED_VOLUME_COUNTER", true );
425  }
426  }
427 
428  // test now orientation
429 
430  std::shared_ptr<std::vector<bool> > elSign ( new std::vector<bool> );
431 
432  Real meshMeasure = checkVolumes ( mesh, *elSign, sw );
433  UInt positive;
434 
435  if ( sw.test ( "SKIP_ORIENTATION_TEST" ) )
436  {
437  if (verbose)
438  {
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;
441  }
442  }
443  else if ( sw.test ( "HAS_NEGATIVE_VOLUMES" ) )
444  {
445  if (verbose)
446  {
447  out << "Checking volume orientation" << std::endl;
448  }
449  positive = count ( elSign->begin(), elSign->end(), true );
450  if ( verbose ) clog << positive << "W: positive elements out of"
451  << mesh.storedVolumes() << std::endl;
452  if ( fix )
453  {
454  if ( verbose )
455  {
456  clog << "Fixing negative elements" << std::endl;
457  }
458  fixVolumes ( mesh, *elSign, sw );
459  }
460 
461  if ( sw.test ( "ABORT_CONDITION" ) )
462  {
463  if (verbose) err << "ABORT: Cannot fix volumes, this element is not supported"
464  << std::endl;
465  return false;
466  }
467  else
468  {
469  sw.unset ( "HAS_NEGATIVE_VOLUMES" );
470  meshMeasure = checkVolumes ( mesh, *elSign, sw );
471  if ( sw.test ( "HAS_NEGATIVE_VOLUMES" ) )
472  {
473  if ( fix )
474  {
475  if ( verbose )
476  {
477  err << "ABORT: Cannot fix volumes: something wrong with this mesh" << std::endl;
478  }
479  sw.create ( "ABORT_CONDITION", true );
480  }
481  return false;
482  }
483  }
484  }
485 
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;
489 
490  //-----------------------------------------------------
491  // BOUNDARY FACES
492  //-----------------------------------------------------
493 
494  std::shared_ptr<MeshUtility::temporaryFaceContainer_Type> bfaces (
495  new MeshUtility::temporaryFaceContainer_Type );
496  UInt numInternalFaces, numFaces;
497 
498  if (verbose)
499  {
500  out << "Finding boundary faces from mesh topology" << std::endl;
501  }
502 
503  UInt bFacesFound = MeshUtility::findBoundaryFaces ( mesh, *bfaces, numInternalFaces );
504 
505  numFaces = bFacesFound + numInternalFaces;
506 
507  MeshUtility::EnquireBFace<RegionMesh> enquireBFace (*bfaces );
508 
509  UInt meshNumBoundaryFaces ( mesh.numBFaces() + mesh.faceList.countElementsWithFlag ( EntityFlags::SUBDOMAIN_INTERFACE, &Flag::testOneSet ) );
510 
511  if ( mesh.storedFaces() == 0 ||
512  meshNumBoundaryFaces > mesh.storedFaces() ||
513  bFacesFound > mesh.storedFaces() || bFacesFound > meshNumBoundaryFaces )
514  {
515  // Something strange with boundary faces
516  if (verbose)
517  {
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;
521  }
522  if ( fix )
523  {
524  sw.create ( "BUILD_BFACES", true );
525  if (verbose)
526  {
527  out << "Building boundary faces from topology data" << std::endl;
528  }
529  MeshUtility::buildFaces ( mesh, clog, err, bFacesFound, numInternalFaces,
530  true, false, false, bfaces.get() );
531  }
532  if (verbose)
533  {
534  err << "After buildFaces" << std::endl;
535  err << "Found " << bFacesFound << " stored " << mesh.storedFaces()
536  << "B faces declared in mesh " << meshNumBoundaryFaces << std::endl;
537  }
538  }
539  else
540  {
541  if ( mesh.storedFaces() == 0 )
542  {
543  if ( verbose )
544  {
545  err << "ABORT CONDITION: cannot find boundary faces" << std::endl;
546  }
547  sw.create ( "NOT_HAS_FACES", true );
548  sw.create ( "ABORT_CONDITION", true );
549  }
550  // The mesh declares to have the correct boundary faces. Yet, are we sure that the flag has been properly set
551  // and that they are stored first? If fix is set we don't trust anybody!
552  //
553  // Make sure that flags are set using the info in bfaces, which depends ONLY on the mesh topology. No messing bout with markers
554  // Make sure BFaces are stored first
555 
556  if (fix)
557  {
558  if (verbose)
559  {
560  out << "Rearranging faces so that boundary faces are first" << std::endl;
561  }
562  MeshUtility::rearrangeFaces ( mesh, clog, err, sw, numFaces, bFacesFound,
563  verbose, bfaces.get() );
564  }
565  if ( meshNumBoundaryFaces != bFacesFound)
566  {
567  if ( verbose )
568  {
569  err << " ERROR: Number of B faces does not correspond to real one" << std::endl;
570  }
571  if (fix)
572  {
573  if ( verbose )
574  {
575  err << "FIXED Number of B faces has been fixed to:" << bFacesFound << std::endl;
576  }
577  mesh.setNumBFaces ( bFacesFound);
578  }
579  }
580 
581  if ( !MeshUtility::checkId ( mesh.faceList ) )
582  {
583  if ( verbose )
584  {
585  err << "ERROR: face ids were wrongly set" << std::endl;
586  err << "FIXED" << std::endl;
587  }
588  if ( fix )
589  {
590  sw.create ( "FIXED_FACES_ID", true );
591  MeshUtility::fixId ( mesh.faceList );
592  }
593  }
594 
595  // Check Consistency with the mesh.
596 
597  if ( fix )
598  {
599  if (verbose)
600  {
601  out << "Make sure that adjacent elements of boundary faces are correct" << std::endl;
602  }
603  MeshUtility::fixBoundaryFaces ( mesh, clog, err, sw, numFaces, bFacesFound,
604  false, verbose, bfaces.get() );
605  }
606 
607 
608 
609  if ( mesh.numBFaces() == 0 )
610  {
611  if ( verbose )
612  {
613  err << " MeshBFaces counter is unset" << std::endl;
614  }
615  if ( fix )
616  {
617  mesh.setNumBFaces ( mesh.storedFaces() );
618  sw.create ( "FIXED_BFACE_COUNTER", true );
619  mesh.setLinkSwitch ( "HAS_BOUNDARY_FACETS" );
620  }
621  }
622 
623 
624  if ( !MeshUtility::checkIsMarkerSet ( mesh.faceList ) )
625  {
626  if (verbose)
627  {
628  out << "Fix markers id for faces" << std::endl;
629  }
630  if ( verbose )
631  {
632  err << "WARNING: Not all faces have marker flag set" << std::endl;
633  }
634  sw.create ( "FACE_MARKER_UNSET", true );
635  if ( fix )
636  {
637  MeshUtility::setBoundaryFacesMarker ( mesh, clog, err, verbose );
638  }
639  if ( fix && MeshUtility::checkIsMarkerSet ( mesh.faceList ) )
640  {
641  sw.create ( "FACE_MARKER_UNSET", false );
642  sw.create ( "FACE_MARKER_FIXED", true );
643  }
644  }
645  }
646 
647 
648  if ( mesh.numFaces() != bFacesFound + numInternalFaces )
649  {
650  if ( verbose )
651  {
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
655  << std::endl;
656  }
657  if ( fix )
658  {
659  if ( verbose )
660  {
661  err << " Fixing" << std::endl;
662  }
663  mesh.setNumFaces ( bFacesFound + numInternalFaces );
664  sw.create ( "FIXED_FACE_COUNTER", true );
665  }
666  }
667 
668  if ( fix && mesh.storedFaces() == bFacesFound + numInternalFaces)
669  {
670  mesh.setLinkSwitch ( "HAS_ALL_FACETS" );
671  }
672 
673  if (verbose)
674  {
675  out << std::endl;
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;
680  out << std::endl;
681  }
682  //-----------------------------------------------------
683  // BOUNDARY EDGES
684  //-----------------------------------------------------
685 
686  std::shared_ptr<MeshUtility::temporaryEdgeContainer_Type> bedges (
687  new MeshUtility::temporaryEdgeContainer_Type );
688 
689  UInt bEdgesFound = MeshUtility::findBoundaryEdges ( mesh, *bedges );
690  MeshUtility::EnquireBEdge<RegionMesh> enquireBEdge (*bedges );
691 
692  UInt intedge (0);
693  UInt Ned (0);
694  MeshUtility::temporaryEdgeContainer_Type iedges;
695 
696  if ( mesh.storedEdges() == 0 ||
697  mesh.numBEdges() > mesh.storedEdges() ||
698  bEdgesFound > mesh.storedEdges() )
699  {
700  if (verbose)
701  {
702  err << "WARNING: mesh does not store (all) boundary edges" << std::endl;
703  }
704  sw.create ( "NOT_HAS_EDGES", true );
705  if ( fix )
706  {
707  if (verbose)
708  {
709  out << "Build boundary edges" << std::endl;
710  }
711  MeshUtility::buildEdges ( mesh, clog, err, bEdgesFound, intedge, true, false,
712  false, bedges.get() );
713  }
714  Ned = bEdgesFound + intedge;
715  if ( fix )
716  {
717  sw.create ( "BUILD_BEDGES", true );
718  }
719  }
720  else
721  {
722 
723  // Make sure BEdges are first
724  // Here I need to use a method that does not require the proper
725  // setting of boundary Points!
726  // With the edges I am being a bit sloppy. I am trusting the given mesh
727  // todo do the same it was done for faces!
728  if ( mesh.numBEdges() != bEdgesFound)
729  {
730  if ( verbose )
731  {
732  err << " ERROR: Number of BEdges does not correspond to real one" << std::endl;
733  }
734  if (fix)
735  {
736  if ( verbose )
737  {
738  err << "FIXED Number of BEdges has been fixed to:" << bEdgesFound << std::endl;
739  }
740  mesh.setNumBEdges ( bEdgesFound);
741  }
742  }
743 
744  if ( fix )
745  {
746  if (verbose)
747  {
748  out << "Reorder edges so that boundary are first" << std::endl;
749  }
750  mesh.edgeList.reorderAccordingToFlag (EntityFlags::PHYSICAL_BOUNDARY, &Flag::testOneSet);
751 
752  sw.create ( "FIXED_BEDGES_FIRST" );
753  }
754  if ( !MeshUtility::checkId ( mesh.edgeList ) )
755  {
756  if ( verbose )
757  {
758  err << "ERROR: edge ids were wrongly set" << std::endl;
759  }
760  if (fix)
761  {
762  if ( verbose )
763  {
764  err << "FIXED" << std::endl;
765  }
766  sw.create ( "FIXED_EDGES_ID", true );
767  MeshUtility::fixId ( mesh.edgeList );
768  }
769  }
770 
771 
772  if ( !MeshUtility::checkIsMarkerSet ( mesh.edgeList ) )
773  {
774  if ( verbose )
775  {
776  err << "WARNING: Not all edges have marker flag set" << std::endl;
777  }
778  sw.create ( "EDGE_MARKER_UNSET", true );
779  if ( fix )
780  {
781  if (verbose)
782  {
783  out << "Fix boundary edges marker" << std::endl;
784  }
785  MeshUtility::setBoundaryEdgesMarker ( mesh, clog, err, verbose );
786  }
787  if ( fix && MeshUtility::checkIsMarkerSet ( mesh.edgeList ) )
788  {
789  sw.unset ( "EDGE_MARKER_UNSET" );
790  sw.create ( "EDGE_MARKER_FIXED", true );
791  }
792  }
793  if (verbose)
794  {
795  out << "Computing number of internal edges";
796  }
797  if ( fix )
798  {
799  Ned = bEdgesFound + MeshUtility::findInternalEdges ( mesh, *bedges, iedges );
800  }
801  }
802  iedges.clear();
803  MeshUtility::temporaryEdgeContainer_Type tmp;
804  iedges.swap (tmp);
805 
806  if ( mesh.numBEdges() != bEdgesFound )
807  {
808  if ( verbose ) err << "WARNING: number of found boundary edges:" << bEdgesFound
809  << std::endl
810  << " does not match that declared in mesh, i.e. "
811  << mesh.numBEdges() << std::endl;
812  if ( mesh.numBEdges() == 0 )
813  {
814  if ( fix )
815  {
816  if ( verbose )
817  {
818  err << "FIXING" << std::endl;
819  }
820  sw.create ( "FIXED_BEDGES_COUNTER", true );
821  mesh.setNumBEdges ( bEdgesFound );
822  }
823  }
824  }
825 
826  if ( Ned != mesh.numEdges() )
827  {
828  if ( fix )
829  {
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 );
834  }
835  }
836  UInt nbed;
837  UInt counte = MeshUtility::testDomainTopology ( mesh, nbed );
838  if ( counte == 0 )
839  {
840  if ( verbose )
841  {
842  out << "**DOMAIN SURFACE IS (TOPOLOGICALLY) CLOSED" << std::endl;
843  }
844  }
845  else
846  {
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;
850  }
851 
852 
853 
854  //-----------------------------------------------------
855  // POINTS
856  //-----------------------------------------------------
857 
858  if (verbose)
859  {
860  out << "Checking vertexes" << std::endl;
861  }
862  UInt numVerticesFound = mesh.pointList.countElementsWithFlag (EntityFlags::VERTEX, &Flag::testOneSet);
863  if (numVerticesFound != mesh.numVertices() )
864  {
865  if ( verbose )
866  {
867  err << "warning: The number of Points with vertex flag on does not coincide with the declared one." << std::endl;
868  }
869  if (fix)
870  {
871  if ( verbose )
872  {
873  err << "It will be fixed now" << std::endl;
874  }
875  // unset the flag. It will be remade
876  for (UInt i = 0; i < mesh.numPoints(); ++i)
877  {
878  mesh.point (i).unSetFlag (EntityFlags::VERTEX);
879  }
880  // Find the real vertices and set the flag
881  for (UInt i = 0; i < mesh.numElements(); ++i)
882  for (UInt j = 0; j < mesh.numLocalVertices(); ++j)
883  {
884  ID k = mesh.element (i).point (j).localId();
885  mesh.pointList (k).setFlag (EntityFlags::VERTEX);
886  }
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 );
894  }
895  }
896 
897  // Now that boundary faces have been correctly set we may work out
898  // boundaty points
899 
900  if (fix)
901  {
902  if (verbose)
903  {
904  out << "Fix boundary points using boundary faces info" << std::endl;
905  }
906  MeshUtility::fixBoundaryPoints (mesh, clog, err, verbose);
907  }
908 
909  MeshUtility::EnquireBPoint<RegionMesh> enquirebpoint ( mesh );
910 
911  UInt foundBPoints = mesh.pointList.countElementsWithFlag (EntityFlags::PHYSICAL_BOUNDARY,
912  &Flag::testOneSet);
913  if (verbose)
914  {
915  out << "B Points Found " << foundBPoints << std::endl;
916  }
917  if ( foundBPoints == 0 || foundBPoints < mesh.storedBPoints() )
918  {
919  if ( verbose )
920  {
921  err << "ERROR Bpoints indicator not correctly set" << std::endl;
922  }
923  }
924  else
925  {
926  if ( fix )
927  {
928  sw.create ( "FIXED_BOUNDARY_POINTS", true );
929  }
930  }
931 
932  // Now that we are sure that (jus) boundary points are flagged as such we check if the marker id is set
933  if (verbose)
934  {
935  out << "Chsck point marker Ids" << std::endl;
936  }
937  if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
938  {
939  if (verbose)
940  {
941  err << "Points MARKER id incorrectly set" << std::endl;
942  }
943 
944  if ( fix )
945  {
946  if ( verbose )
947  {
948  err << " Fixing Points Marker ID" << std::endl << "If unset the boundary will inherit the strongest among faces" << std::endl;
949  }
950  if ( verbose )
951  {
952  err << " The internal will be set to the domain flag" << std::endl;
953  }
954  MeshUtility::setBoundaryPointsMarker ( mesh, clog, err, false );
955  // fix marker at interior points. It takes
956  if ( ! MeshUtility::checkIsMarkerSet ( mesh.pointList ) )
957  {
958  // Maybe boundary points marker is fine, this is enough
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();
965  it < listOfPt.end();
966  ++it)
967  {
968  boundaryIsOk = boundaryIsOk | (*it)->isMarkerSet();
969  }
970  std::vector<point_Type const*>().swap (listOfPt); // save memory
971  if ( verbose )
972  {
973  clog << " Marker ID on boundary points is fine. Internal points may have marker unset" << std::endl;
974  }
975  if (verbose)
976  {
977  err << "Cannot Fix Points MARKER" << std::endl;
978  }
979  if ( verbose && boundaryIsOk )
980  {
981  err << "But boundary points are fine" << std::endl;
982  }
983  sw.create ( "POINT_MARKER_UNSET", true );
984  }
985  else
986  {
987  if (verbose)
988  {
989  err << "FIXED" << std::endl;
990  }
991  sw.create ( "FIXED_POINT_MARKER", true );
992  }
993  }
994  }
995 
996 
997  if ( mesh.storedBPoints() == 0 )
998  {
999  if ( verbose )
1000  {
1001  err << "WARNING B. Points COUNTER incorrectly set" << std::endl;
1002  }
1003  if ( fix )
1004  {
1005  MeshUtility::setBoundaryPointsCounters ( mesh ) ;
1006  if ( verbose )
1007  {
1008  err << " FIXED" << std::endl;
1009  }
1010  sw.create ( "FIXED_BPOINTS_COUNTER", true );
1011  }
1012  }
1013 
1014  if ( mesh.numPoints() == 0 )
1015  {
1016  if ( verbose )
1017  {
1018  err << "WARNING Points Counter unset" << std::endl;
1019  }
1020  if ( fix )
1021  {
1022  mesh.numPoints() = mesh.storedPoints();
1023  sw.create ( "FIXED_POINTS_COUNTER", true );
1024  }
1025  }
1026 
1027  //-----------------------------------------------------
1028  // FINAL CHECKS
1029  //-----------------------------------------------------
1030  if ( verbose ) out << " ******** COUNTERS CONTENT **********************************" << std::endl
1031 
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 **********************************"
1042  << std::endl;
1043 
1044  bool eulok1 = ( 2 * mesh.numFaces() -
1045  mesh.numLocalFaces() * mesh.numVolumes() -
1046  mesh.numBFaces() ) == 0;
1047 
1048  bool eulok2 ( true );
1049 
1050  if ( RegionMesh::elementShape_Type::S_shape == TETRA )
1051  {
1052  if ( verbose )
1053  {
1054  out << std::endl << "Checking Euler formulae: ";
1055  }
1056  eulok2 = ( mesh.numEdges() -
1057  mesh.numVolumes() -
1058  mesh.numVertices() -
1059  ( 3 * mesh.numBFaces() -
1060  2 * mesh.numBVertices() ) / 4 ) == 0;
1061  }
1062 
1063  if ( ! ( eulok1 && eulok2 ) )
1064  {
1065  if ( verbose ) err << "WARNING: The following Euler formula(s) are not satisfied"
1066  << std::endl;
1067  sw.create ( "NOT_EULER_OK" );
1068  }
1069  else
1070  {
1071  if ( verbose )
1072  {
1073  out << std::endl << " ok." << std::endl;
1074  }
1075  }
1076 
1077  if ( !eulok1 )
1078  {
1079  if ( verbose ) err << " 2*nFaces = nFacesPerVolume*nVolumes + nBoundaryFaces"
1080  << std::endl
1081  << " 2*" << mesh.numFaces() << " != " << mesh.numLocalFaces()
1082  << " * " << mesh.numVolumes() << " + " << mesh.numBFaces()
1083  << std::endl;
1084  }
1085 
1086  if ( !eulok2 )
1087  {
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;
1092  }
1093 
1094  mesh.setLinkSwitch ( "HAS_BEEN_CHECKED" );
1095 
1096  return true;
1097 }
1098 }
1099 #endif
I use standard constructor/destructors.
Definition: Switch.hpp:50
GetCoordComponent(Int i)
Constructor taking the component.
Definition: MeshUtility.cpp:49
void create(const char *a, bool status=false)
Definition: Switch.cpp:126
This functor is used to do some geometry checks.
uint32_type ID
IDs.
Definition: LifeV.hpp:194
Real testClosedDomain(RegionMesh const &mesh, std::ostream &err=std::cerr)
Tests if the surface of the mesh is closed by computing surface integrals.
Definition: MeshChecks.hpp:252
#define ASSERT0(X, A)
Definition: LifeAssert.hpp:71
void getVolumeFromFaces(RegionMesh const &mesh, Real vols[3], std::ostream &err=std::cerr)
Computes volume enclosed by boundary faces.
Definition: MeshChecks.hpp:202
double Real
Generic real data.
Definition: LifeV.hpp:175
CurrentFE - A primordial class for the assembly of the local matrices/vectors retaining the values on...
Definition: CurrentFE.hpp:243
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.
Definition: MeshChecks.hpp:316
Real checkVolumes(RegionMesh const &mesh, std::vector< bool > &elSign, Switch &sw)
Report 3D element orientation.
Definition: MeshChecks.hpp:111
void fixVolumes(RegionMesh &mesh, const std::vector< bool > &elSign, Switch &sw)
Fixes negative volume elements.
Definition: MeshChecks.hpp:175