LifeV
ParserINRIAMesh.hpp
Go to the documentation of this file.
1 /********************************************************************************
2  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
3  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
4 
5  This file is part of LifeV.
6 
7  LifeV is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  LifeV is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public License
18  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
19 ********************************************************************************/
20 
21 /**
22  * @file INRIAMeshParser.hpp
23  * @brief INRIA (Freefem++) mesh files (.mesh) reader.
24  * @author Antonio Cervone <ant.cervone@gmail.com>
25  * @date 10/2012
26 **/
27 
28 #ifndef PARSER_INRIA_MESH_HPP__
29 #define PARSER_INRIA_MESH_HPP__
30 
31 #include <lifev/core/LifeV.hpp>
32 #include <lifev/core/mesh/BareMesh.hpp>
33 #include <lifev/core/mesh/InternalEntitySelector.hpp>
34 
35 #include <fstream>
36 
37 namespace LifeV
38 {
39 
40 namespace MeshIO
41 {
42 
43 namespace
44 {
45 
46 // ===================================================
47 // INRIA mesh readers
48 // ===================================================
49 
50 //! nextIntINRIAMeshField -
51 /*!
52  It gets an integer field from the std::string line
53  if it is not empty, otherwise from the input stream.
54  It assumes that the std::string is either empty or
55  it contains and integer. No check is made to verify this.
56 
57  @param line, the mesh data structure to fill in.
58  @param myStream, the name of the mesh file to read.
59  @return true if everything went fine, false otherwise.
60 */
61 Int
62 nextIntINRIAMeshField ( std::string const& line,
63  std::istream& myStream )
64 {
65  /*
66  first control if line has something.
67  If so use atoi (the version from util_string.h)
68  to extract the integer.
69  Otherwise get if from the input stream
70  */
71 
72  for ( std::string::const_iterator is = line.begin(); is != line.end(); ++is )
73  {
74  if ( *is != ' ' )
75  {
76  return atoi ( line );
77  }
78  }
79  Int dummy;
80  myStream >> dummy;
81 
82  return dummy;
83 }// Function nextIntINRIAMeshField
84 
85 //! readINRIAMeshFileHead - It Reads all basic info from INRIA MESH.
86 /*!
87  It Reads all basic info from INRIA MESH file
88  so as to be able to properly dimension all arrays
89 
90  @param myStream,
91  @param numberVertices,
92  @param numberBoundaryVertices,
93  @param numberBoundaryFaces,
94  @param numberBoundaryEdges,
95  @param numberVolumes,
96  @param numberStoredFaces,
97  @param shape,
98  @param iSelect,
99  @return false if mesh check is unsuccessfull.
100 */
101 bool
102 readINRIAMeshFileHead ( std::ifstream& myStream,
103  UInt& numberVertices,
104  UInt& numberBoundaryVertices,
105  UInt& numberBoundaryFaces,
106  UInt& numberBoundaryEdges,
107  UInt& numberVolumes,
108  UInt& numberStoredFaces,
109  ReferenceShapes& shape,
110  InternalEntitySelector iSelect )
111 {
112  const int idOffset = 1; //IDs in INRIA files start from 1
113 
114  numberVertices = 0;
115  numberBoundaryVertices = 0;
116  numberBoundaryFaces = 0;
117  numberBoundaryEdges = 0;
118  numberVolumes = 0;
119  numberStoredFaces = 0;
120 
121  std::string line;
122 
123  Real x, y, z;
124 
125  Int idummy;
126 
127  UInt i, ibc;
128  UInt done = 0;
129  UInt p1, p2, p3, p4, p5, p6, p7, p8;
130  UInt numReadFaces = 0;
131  numberStoredFaces = 0;
132 
133  //shape = NONE;
134  std::vector<bool> isboundary;
135  //streampos start=myStream.tellg();
136 
137  while ( nextGoodLine ( myStream, line ).good() )
138  {
139  if ( line.find ( "MeshVersionFormatted" ) != std::string::npos )
140  {
141  idummy = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "d" ) + 1 ), myStream );
142  ASSERT_PRE0 ( idummy == 1, "I can read only formatted INRIA Mesh files, sorry" );
143  }
144 
145  if ( line.find ( "Dimension" ) != std::string:: npos )
146  {
147  idummy = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "n" ) + 1 ), myStream );
148  ASSERT_PRE0 ( idummy == 3, "I can read only 3D INRIA Mesh files, sorry" );
149  }
150 
151  // I assume that internal vertices have their Ref value set to 0 (not clear from medit manual)
152  if ( line.find ( "Vertices" ) != std::string::npos )
153  {
154  numberVertices = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
155  done++;
156  numberBoundaryVertices = 0;
157  isboundary.resize ( numberVertices, false );
158 
159  for ( i = 0; i < numberVertices; ++i )
160  {
161  myStream >> x >> y >> z >> ibc;
162  if ( ! iSelect ( markerID_Type ( ibc ) ) )
163  {
164  numberBoundaryVertices++;
165  isboundary[ i ] = true;
166  }
167  }
168  }
169 
170  if ( line.find ( "Triangles" ) != std::string::npos )
171  {
172  ASSERT_PRE0 ( shape != HEXA, " Cannot have triangular faces in an HEXA INRIA MESH" );
173  shape = TETRA;
174  numReadFaces = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
175  numberBoundaryFaces = 0;
176 
177  done++;
178 
179  for ( UInt k = 0; k < numReadFaces; k++ )
180  {
181  myStream >> p1 >> p2 >> p3 >> ibc;
182  if ( isboundary[ p1 - idOffset ] && isboundary [ p2 - idOffset ] && isboundary[ p3 - idOffset ])
183  {
184  if ( iSelect ( markerID_Type ( ibc ) ) )
185  {
186  std::cerr << "ATTENTION: Face (1-based numbering) "
187  << p1 << " "
188  << p2 << " "
189  << p3 << " has all vertices on the boundary yet is marked as interior: "
190  << ibc << std::endl;
191  }
192  ++numberBoundaryFaces;
193  }
194  else
195  {
196  if ( !iSelect ( markerID_Type ( ibc ) ) )
197  {
198  std::cerr << "ATTENTION: Face (1-based numbering) "
199  << p1 << " "
200  << p2 << " "
201  << p3
202  << " has vertices in the interior yet is marked as boundary: "
203  << ibc << std::endl;
204  }
205  }
206  }
207  numberStoredFaces = numReadFaces;
208  }
209 
210 
211  if ( line.find ( "Quadrilaterals" ) != std::string::npos )
212  {
213  ASSERT_PRE0 ( shape != TETRA, " Cannot have quad faces in an TETRA INRIA MESH" );
214  shape = HEXA;
215  numReadFaces = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
216  done++;
217  numberBoundaryFaces = 0;
218 
219  for ( UInt k = 0; k < numReadFaces; k++ )
220  {
221  myStream >> p1 >> p2 >> p3 >> p4 >> ibc;
222  if ( isboundary[ p1 - idOffset ] && isboundary[ p2 - idOffset ]
223  && isboundary[ p3 - idOffset ] && isboundary[ p4 - idOffset ] )
224  {
225  if ( iSelect ( markerID_Type ( ibc ) ) )
226  {
227  std::cerr << "ATTENTION: Face (1-based numbering) "
228  << p1 << " "
229  << p2 << " "
230  << p3 << " "
231  << p4
232  << " has all vertices on the boundary yet is marked as interior: "
233  << ibc << std::endl;
234  }
235  ++numberBoundaryFaces;
236  }
237 
238  }
239  numberStoredFaces = numReadFaces;
240  }
241  // To cope with a mistake in INRIA Mesh files
242  if ( line.find ( "Tetrahedra" ) != std::string::npos )
243  {
244  ASSERT_PRE0 ( shape != HEXA, " Cannot have tetras in a HEXA INRIA MESH" );
245  shape = TETRA;
246  numberVolumes = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "a" ) + 1 ), myStream );
247  done++;
248 
249  for ( i = 0; i < numberVolumes; i++ )
250  {
251  myStream >> p1 >> p2 >> p3 >> p4 >> ibc;
252  }
253  }
254 
255  if ( line.find ( "Hexahedra" ) != std::string::npos )
256  {
257  ASSERT_PRE0 ( shape != TETRA, " Cannot have Hexahedra in a TETRA INRIA MESH" );
258  shape = HEXA;
259  numberVolumes = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "a" ) + 1 ), myStream );
260  done++;
261 
262  for ( i = 0; i < numberVolumes; i++ )
263  {
264  myStream >> p1 >> p2 >> p3 >> p4 >> p5 >> p6 >> p7 >> p8 >> ibc;
265  }
266  }
267  // I assume we are storing only boundary edges
268  if ( line.find ( "Edges" ) != std::string::npos )
269  {
270  numberBoundaryEdges = nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
271  done++;
272  for ( i = 0; i < numberBoundaryEdges; i++ )
273  {
274  myStream >> p1 >> p2 >> ibc;
275  }
276  }
277  }
278 
279  LIFEV_UNUSED (idummy);
280  return true ;
281 }// Function readINRIAMeshFileHead
282 
283 }
284 
285 //! INRIAMeshRead - reads .mesh meshes.
286 /*!
287  @param bareMesh, the bareMesh data structure to fill in.
288  @param fileName, the name of the mesh file to read.
289  @param regionFlag, the identifier for the region.
290  @param verbose, setting it as true, the output is verbose (the default is false).
291  @param iSelect,
292  @return true if everything went fine, false otherwise.
293 */
294 template <typename GeoShape>
295 bool
296 ReadINRIAMeshFile ( BareMesh<GeoShape>& bareMesh,
297  std::string const& fileName,
298  markerID_Type regionFlag,
299  bool verbose = false,
300  InternalEntitySelector iSelect = InternalEntitySelector() )
301 {
302  const int idOffset = 1; //IDs in INRIA meshes start from 1
303 
304  std::string line, faceName, volumeName;
305 
306  Real x, y, z;
307  ID buffer;
308 
309  UInt done = 0;
310  UInt numberPoints, numberBoundaryPoints;
311  UInt numberVertices, numberBoundaryVertices;
312  UInt numberEdges, numberBoundaryEdges;
313  UInt numberBoundaryFaces, numberStoredFaces;
314  UInt numberVolumes;
315 
316  std::stringstream discardedLog;
317 
318  ReferenceShapes shape ( NONE );
319 
320  std::ostream& oStr = verbose ? std::cout : discardedLog;
321 
322  // open stream to read header
323 
324  std::ifstream hstream ( fileName.c_str() );
325 
326  if ( verbose )
327  {
328  std::cout << "Reading from file " << fileName << std::endl;
329  }
330 
331  if ( hstream.fail() )
332  {
333  std::cerr << " Error in readINRIAMeshFile = file " << fileName
334  << " not found or locked" << std::endl;
335  std::abort();
336  }
337 
338  if ( verbose )
339  {
340  std::cout << "Reading INRIA mesh file" << fileName << std::endl;
341  }
342 
343  if ( ! MeshIO::readINRIAMeshFileHead ( hstream, numberVertices, numberBoundaryVertices,
344  numberBoundaryFaces, numberBoundaryEdges,
345  numberVolumes, numberStoredFaces, shape, iSelect) )
346  {
347  std::cerr << " Error while reading INRIA mesh file headers" << std::endl;
348  std::abort() ;
349  }
350 
351  hstream.close();
352 
353  //Reopen the stream: I know it is stupid but this is how it goes
354  std::ifstream myStream ( fileName.c_str() );
355 
356  if ( myStream.fail() )
357  {
358  std::cerr << " Error in readINRIAMeshFile = file " << fileName
359  << " not found or locked" << std::endl;
360  std::abort();
361  }
362 
363  ASSERT_PRE0 ( GeoShape::S_shape == shape, "INRIA Mesh file and mesh element shape is not consistent" );
364 
365  numberPoints = numberVertices;
366  numberBoundaryPoints = numberBoundaryVertices;
367 
368  // Be a little verbose
369  switch ( shape )
370  {
371  case HEXA:
372  ASSERT_PRE0 ( GeoShape::S_numPoints == 8, "Sorry I can read only linear Hexa meshes" );
373  if ( verbose )
374  {
375  std::cout << "Linear Hexa mesh" << std::endl;
376  }
377  faceName = "Quadrilaterals";
378  volumeName = "Hexahedra";
379  break;
380 
381  case TETRA:
382  if ( GeoShape::S_numPoints == 4 )
383  {
384  if ( verbose )
385  {
386  std::cout << "Linear Tetra Mesh" << std::endl;
387  }
388  }
389  else if ( GeoShape::S_numPoints == 10 )
390  {
391  if ( verbose )
392  {
393  std::cout << "Quadratic Tetra mesh (from linear geometry)" << std::endl;
394  }
395  numberPoints += numberEdges;
396  numberBoundaryPoints += numberBoundaryEdges;
397  }
398  else
399  {
400  ERROR_MSG ( "mesh type not supported" );
401  }
402 
403  faceName = "Triangles";
404  volumeName = "Tetrahedra";
405  break;
406  default:
407  ERROR_MSG ( "Current version of INRIA Mesh file reader only accepts TETRA and HEXA" );
408  }
409 
410  // Set all basic data structure
411  bareMesh.numBoundaryPoints = numberBoundaryPoints;
412  bareMesh.numVertices = numberVertices;
413  bareMesh.numBoundaryVertices = numberBoundaryVertices;
414  bareMesh.points.reshape ( 3, numberPoints );
415  bareMesh.pointMarkers.resize ( numberPoints );
416  bareMesh.pointIDs.resize ( numberPoints );
417 
418  bareMesh.ridges.reshape ( GeoShape::GeoBShape::GeoBShape::S_numPoints, numberBoundaryEdges );
419  bareMesh.ridgeMarkers.resize ( numberBoundaryEdges );
420  bareMesh.ridgeIDs.resize ( numberBoundaryEdges );
421 
422  bareMesh.numBoundaryFacets = numberBoundaryFaces;
423  bareMesh.facets.reshape ( GeoShape::GeoBShape::S_numPoints, numberStoredFaces );
424  bareMesh.facetMarkers.resize ( numberStoredFaces );
425  bareMesh.facetIDs.resize ( numberStoredFaces );
426 
427  bareMesh.elements.reshape ( GeoShape::S_numPoints, numberVolumes );
428  bareMesh.elementMarkers.resize ( numberVolumes );
429  bareMesh.elementIDs.resize ( numberVolumes );
430 
431  bareMesh.regionMarkerID = regionFlag;
432 
433  UInt count = 0;
434  Int ibc;
435 
436  // To account for internal faces
437  if ( numberStoredFaces > numberBoundaryFaces )
438  {
439  oStr << "WARNING: The mesh file (apparently) contains "
440  << numberStoredFaces - numberBoundaryFaces << " internal faces" << std::endl;
441  }
442 
443  while ( nextGoodLine ( myStream, line ).good() )
444  {
445  if ( line.find ( "Vertices" ) != std::string::npos )
446  {
447  nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
448 
449  for ( UInt i = 0; i < numberVertices; i++ )
450  {
451  myStream >> x >> y >> z >> ibc;
452 
453  if ( !iSelect (markerID_Type (ibc) ) )
454  {
455  ++count;
456  }
457 
458  bareMesh.points ( 0, i ) = x;
459  bareMesh.points ( 1, i ) = y;
460  bareMesh.points ( 2, i ) = z;
461  bareMesh.pointMarkers[ i ] = ibc;
462  bareMesh.pointIDs[i] = i;
463  }
464  done++;
465 
466  if ( count != numberBoundaryVertices )
467  {
468  std::cerr << "Number boundary points inconsistent!" << std::endl;
469  }
470  }
471 
472  if ( line.find ( faceName ) != std::string::npos )
473  {
474  nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
475  oStr << "Reading boundary faces " << std::endl;
476 
477  for ( UInt i = 0; i < numberStoredFaces; i++ )
478  {
479  for ( UInt k = 0; k < GeoShape::GeoBShape::S_numPoints; k++ )
480  {
481  myStream >> buffer;
482  bareMesh.facets ( k, i ) = buffer - idOffset;
483  }
484  myStream >> ibc;
485  bareMesh.facetMarkers[ i ] = ibc;
486  bareMesh.facetIDs[ i ] = i;
487  }
488 
489  oStr << "Boundary faces read " << std::endl;
490  done++;
491  }
492 
493  if ( line.find ( "Edges" ) != std::string::npos )
494  {
495  nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "s" ) + 1 ), myStream );
496  oStr << "Reading boundary edges " << std::endl;
497 
498  for ( UInt i = 0; i < numberBoundaryEdges; i++ )
499  {
500  for ( UInt k = 0; k < GeoShape::GeoBShape::GeoBShape::S_numPoints; k++ )
501  {
502  myStream >> buffer;
503  bareMesh.ridges ( k, i ) = buffer - idOffset;
504  }
505  myStream >> ibc;
506  bareMesh.ridgeMarkers[ i ] = ibc;
507  bareMesh.ridgeIDs[ i ] = i;
508  }
509  oStr << "Boundary edges read " << std::endl;
510  done++;
511  }
512 
513  if ( line.find ( volumeName ) != std::string::npos )
514  {
515  count = 0;
516  nextIntINRIAMeshField ( line.substr ( line.find_last_of ( "a" ) + 1 ), myStream );
517  oStr << "Reading volumes " << std::endl;
518 
519  for ( UInt i = 0; i < numberVolumes; i++ )
520  {
521  for ( UInt k = 0; k < GeoShape::S_numPoints; k++ )
522  {
523  myStream >> buffer;
524  bareMesh.elements ( k, i ) = buffer - idOffset;
525  }
526  myStream >> ibc;
527  bareMesh.elementMarkers[ i ] = ibc;
528  bareMesh.elementIDs[ i ] = i;
529  count++;
530  }
531  oStr << count << " Volume elements read" << std::endl;
532  done++;
533  }
534  }
535 
536  myStream.close();
537  return done == 4 ;
538 }
539 
540 } // GmshIO
541 
542 } // LifeV
543 
544 #endif // PARSER_INRIA_MESH_HPP__
#define ASSERT_PRE0(X, A)
Definition: LifeAssert.hpp:72
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
ID markerID_Type
markerID_Type is the type used to store the geometric entity marker IDs
Definition: Marker.hpp:81
#define ERROR_MSG(A)
Definition: LifeAssert.hpp:69
uint32_type ID
IDs.
Definition: LifeV.hpp:194
double Real
Generic real data.
Definition: LifeV.hpp:175
#define LIFEV_UNUSED(x)
Definition: LifeV.hpp:125
Assert & error(const char *strMsg=0)
A struct for a bare mesh.
Definition: BareMesh.hpp:53
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191