Chaste  Release::3.4
GmshMeshReader.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 #include <cassert>
36 #include <sstream>
37 #include <iostream>
38 
39 #include "GmshMeshReader.hpp"
40 #include "Exception.hpp"
41 
42 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
44  unsigned orderOfElements,
45  unsigned orderOfBoundaryElements) :
46  mFileName(pathBaseName),
47  mOrderOfElements(orderOfElements),
48  mOrderOfBoundaryElements(orderOfBoundaryElements)
49 {
50  assert(SPACE_DIM==ELEMENT_DIM); //There is no fundamental reason for this, but full testing of SPACE_DIM != ELEMENT_DIM would be required.
51 
52  // Only linear and quadratic elements
53  assert(mOrderOfElements==1 || mOrderOfElements==2);
54 
55  if (mOrderOfElements==1)
56  {
57  mNodesPerElement = ELEMENT_DIM+1;
58  }
59  else
60  {
61  mNodesPerElement = (ELEMENT_DIM+1)*(ELEMENT_DIM+2)/2;
62  }
63 
65  {
66  mNodesPerBoundaryElement = ELEMENT_DIM;
67  }
68  else
69  {
70  mNodesPerBoundaryElement = ELEMENT_DIM*(ELEMENT_DIM+1)/2;
71  }
72 
73  OpenFiles();
74  ReadHeaders();
75 }
76 
77 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
79 {
80  CloseFiles();
81 }
82 
83 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
85 {
86  // Open mesh file
87  mNodeFile.open(mFileName.c_str());
88  mElementFile.open(mFileName.c_str());
89  mFaceFile.open(mFileName.c_str());
90  if (!mNodeFile.is_open() || !mElementFile.is_open() || !mFaceFile.is_open() )
91  {
92  EXCEPTION("Could not open data file: " + mFileName);
93  }
94 }
95 
96 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
98 {
99  mNodeFile.close();
100  mElementFile.close();
101  mFaceFile.close();
102 }
103 
104 
105 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
107 {
108  /*
109  * Read mesh format information from the file header
110  */
111  std::string this_line;
112  getline(mNodeFile, this_line);
113 
114  assert(this_line == "$MeshFormat");
115 
116  //Read the version no.
117  getline(mNodeFile, this_line);
118  std::stringstream line(this_line);
119 
120  line >> mVersionNumber >> mFileType >> mDataSize;
121 
122  if(mVersionNumber != 2.2)
123  {
124  EXCEPTION("Only .msh version 2.2 files are supported.");
125  }
126  assert(mFileType == 0);
127 
128  //Check mesh format close string
129  getline(mNodeFile, this_line);
130  assert(this_line == "$EndMeshFormat");
131 
132  ReadNodeHeader();
133  ReadElementHeader(); // This reads the total number of elements in the file into mTotalNumElementsAndFaces
134  ReadFaceHeader();
135 
136  if (mTotalNumElementsAndFaces != mNumElements + mNumFaces)
137  {
138  EXCEPTION("Unrecognised element types present in the .msh file: check mesh generation settings in gmsh.");
139  // If you hit this, then the .msh file lists elements that are not simply
140  // in 2D:
141  // linear/quadratic lines for faces, triangles for elements
142  // in 3D:
143  // linear/quadratic traingles for faces, tets for elements.
144  // which probably means something funny happened in the mesh generation.
145  }
146 }
147 
148 
149 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
151 {
152  //search for the start of the node section
153  std::string this_line;
154  std::stringstream line(this_line);
155 
156  while(this_line != "$Nodes")
157  {
158  getline(mNodeFile, this_line);
159  }
160  getline(mNodeFile, this_line);
161 
162  line.clear();
163  line.str(this_line);
164  line >> mNumNodes; //mNodesFile should now be pointing at the start of the node lines in the file.
165 }
166 
167 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
169 {
170  //Search for the start of the elements section
171  std::string this_line;
172  std::stringstream line(this_line);
173 
174  getline(mElementFile, this_line);
175  while(this_line != "$Elements")
176  {
177  getline(mElementFile, this_line);
178  }
179  getline(mElementFile, this_line); //Throw away the line that says the number of elements specified in the file
180  line.clear();
181  line.str(this_line);
182  line >> mTotalNumElementsAndFaces;
183  int ele_start = mElementFile.tellg(); //Pointer to the start of the element block.
184 
185  mNumElements = 0u;
186  getline(mElementFile, this_line);
187 
188  while(this_line != "$EndElements")
189  {
190  line.clear();
191  line.str(this_line);
192 
193  unsigned ele_index;
194  unsigned ele_type;
195  line >> ele_index >> ele_type;
196 
197  if(ELEMENT_DIM == 2 && (ele_type == GmshTypes::TRIANGLE || ele_type == GmshTypes::QUADRATIC_TRIANGLE))
198  {
199  mNumElements++;
200  }
201  else if(ELEMENT_DIM == 3 && (ele_type == GmshTypes::TETRAHEDRON || ele_type == GmshTypes::QUADRATIC_TETRAHEDRON))
202  {
203  mNumElements++;
204  }
205 
206  getline(mElementFile, this_line);
207  }
208 
209  mElementFile.seekg(ele_start); //mElementFile should now be pointing at the start of the node lines in the file.
210 }
211 
212 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
214 {
215  //Search for the start of the elements section
216  std::string this_line;
217  std::stringstream line(this_line);
218 
219  getline(mFaceFile, this_line);
220  while(this_line != "$Elements")
221  {
222  getline(mFaceFile, this_line);
223  }
224  getline(mFaceFile, this_line); // Throw away the line that says the number of elements specified in the file
225  int face_start = mFaceFile.tellg(); // Pointer to the start of the element block.
226 
227  mNumFaces = 0u;
228  getline(mFaceFile, this_line);
229 
230  while(this_line != "$EndElements")
231  {
232  line.clear();
233  line.str(this_line);
234 
235  unsigned ele_index;
236  unsigned ele_type;
237  line >> ele_index >> ele_type;
238 
239  if(ELEMENT_DIM == 2 && (ele_type == GmshTypes::LINE || ele_type == GmshTypes::QUADRATIC_LINE))
240  {
241  mNumFaces++;
242  }
243  else if(ELEMENT_DIM == 3 && (ele_type == GmshTypes::TRIANGLE || ele_type == GmshTypes::QUADRATIC_TRIANGLE))
244  {
245  mNumFaces++;
246  }
247 
248  getline(mFaceFile, this_line);
249  }
250 
251  mFaceFile.seekg(face_start); //mFacesFile should now be pointing at the start of the node lines in the file.
252 }
253 
254 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
256 {
257  return mNumElements;
258 }
259 
260 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
262 {
263  return mNumNodes;
264 }
265 
266 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
268 {
269  return mNumFaces;
270 }
271 
272 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
274 {
276  //return mNumCableElements;
277 }
278 
279 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
281 {
282  return mOrderOfElements;
283 }
284 
285 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
287 {
288  return mOrderOfBoundaryElements;
289 }
290 
291 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
293 {
294  return mNumElementAttributes;
295 }
296 
297 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
299 {
300  return mNumFaceAttributes;
301 }
302 
303 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
305 {
307  //return mNumCableElementAttributes;
308 }
309 
310 
311 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
313 {
314  CloseFiles();
315 
316  OpenFiles();
317  ReadHeaders();
318 }
319 
320 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
322 {
323  std::vector<double> ret_coords(SPACE_DIM);
324 
325  std::string this_line;
326  getline(mNodeFile, this_line);
327 
328  std::stringstream line(this_line);
329 
330  unsigned node_index;
331  line >> node_index >> ret_coords[0] >> ret_coords[1];
332 
333  if(ELEMENT_DIM == 3)
334  {
335  line >> ret_coords[2];
336  }
337 
338  return ret_coords;
339 }
340 
341 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
343 {
344  return std::vector<double>(0);
345 }
346 
347 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
349 {
350  ElementData element_data;
351  element_data.NodeIndices.resize(mNodesPerElement);
352  element_data.AttributeValue = 0.0; // If an attribute is not read this stays as zero, otherwise overwritten.
353 
354  std::string this_line;
355  std::stringstream line(this_line);
356 
357  unsigned ele_index;
358  unsigned ele_type;
359  unsigned ele_attributes=0;
360  bool volume_element_found = false;
361 
362  while(!volume_element_found)
363  {
364  getline(mElementFile, this_line);
365  line.clear();
366  line.str(this_line);
367 
368  line >> ele_index >> ele_type >> ele_attributes;
369 
370  if((ELEMENT_DIM == 2 && (ele_type == GmshTypes::TRIANGLE || ele_type == GmshTypes::QUADRATIC_TRIANGLE) ) ||
371  (ELEMENT_DIM == 3 && (ele_type == GmshTypes::TETRAHEDRON || ele_type == GmshTypes::QUADRATIC_TETRAHEDRON)))
372  {
373  volume_element_found = true;
374  }
375  }
376 
377  //Gmsh can have arbitrary numbers of element attributes, but Chaste only handles one. We pick the first attribute and throw
378  //away the remainder.
379  if(ele_attributes > 0)
380  {
381  mNumElementAttributes = 1u;
382  line >> element_data.AttributeValue;
383  }
384  unsigned unused_attr;
385  for(unsigned attr_index = 0; attr_index < (ele_attributes-1); ++attr_index)
386  {
387  line >> unused_attr;
388  }
389 
390  //Read the node indices
391  for(unsigned node_index = 0; node_index < mNodesPerElement; ++node_index)
392  {
393  line >> element_data.NodeIndices[node_index];
394 
395  element_data.NodeIndices[node_index]--; //Gmsh *always* indexes from 1, we index from 0
396  }
397 
398  return element_data;
399 }
400 
401 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
403 {
405 }
406 
407 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
409 {
410  ElementData face_data;
411  face_data.NodeIndices.resize(mNodesPerBoundaryElement);
412  face_data.AttributeValue = 0.0; // If an attribute is not read this stays as zero, otherwise overwritten.
413 
414  std::string this_line;
415  std::stringstream line(this_line);
416 
417  unsigned face_index;
418  unsigned face_type;
419  unsigned face_attributes=0;
420  bool surface_element_found = false;
421 
422  while(!surface_element_found)
423  {
424  getline(mFaceFile, this_line);
425  line.clear();
426  line.str(this_line);
427 
428  line >> face_index >> face_type >> face_attributes;
429 
430  if((ELEMENT_DIM == 2 && (face_type == GmshTypes::LINE || face_type == GmshTypes::QUADRATIC_LINE) ) ||
431  (ELEMENT_DIM == 3 && (face_type == GmshTypes::TRIANGLE || face_type == GmshTypes::QUADRATIC_TRIANGLE)))
432  {
433  surface_element_found = true;
434  }
435  }
436 
437  //Gmsh can have arbitrary numbers of element attributes, but Chaste only handles one. We pick the first attribute and throw
438  //away the remainder.
439  if(face_attributes > 0)
440  {
441  mNumFaceAttributes = 1u;
442  line >> face_data.AttributeValue;
443  }
444  unsigned unused_attr;
445  for(unsigned attr_index = 0; attr_index < (face_attributes-1); ++attr_index)
446  {
447  line >> unused_attr;
448  }
449 
450  //Read the node indices
451  for(unsigned node_index = 0; node_index < mNodesPerBoundaryElement; ++node_index)
452  {
453  line >> face_data.NodeIndices[node_index];
454 
455  face_data.NodeIndices[node_index]--; //Gmsh *always* indexes from 1, we index from 0
456  }
457 
458  return face_data;
459 }
460 
461 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
462 std::vector<double> GmshMeshReader<ELEMENT_DIM, SPACE_DIM>::GetNode(unsigned index)
463 {
465 }
466 
467 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
469 {
471 }
472 
473 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
475 {
477 }
478 
480 // Explicit instantiation
482 
483 template class GmshMeshReader<0,1>;
484 template class GmshMeshReader<1,1>;
485 template class GmshMeshReader<1,2>;
486 template class GmshMeshReader<1,3>;
487 template class GmshMeshReader<2,2>;
488 template class GmshMeshReader<2,3>;
489 template class GmshMeshReader<3,3>;
unsigned GetNumElements() const
unsigned GetOrderOfBoundaryElements()
unsigned GetNumFaceAttributes() const
unsigned mOrderOfBoundaryElements
ElementData GetFaceData(unsigned index)
ElementData GetNextCableElementData()
unsigned mNodesPerBoundaryElement
unsigned GetOrderOfElements()
ElementData GetNextFaceData()
#define EXCEPTION(message)
Definition: Exception.hpp:143
#define NEVER_REACHED
Definition: Exception.hpp:206
ElementData GetNextElementData()
std::vector< unsigned > NodeIndices
unsigned GetNumFaces() const
std::vector< double > GetNodeAttributes()
ElementData GetElementData(unsigned index)
GmshMeshReader(std::string pathBaseName, unsigned orderOfElements=1, unsigned orderOfBoundaryElements=1)
std::vector< double > GetNode(unsigned index)
unsigned GetNumCableElements() const
unsigned GetNumElementAttributes() const
unsigned mOrderOfElements
unsigned GetNumCableElementAttributes() const
unsigned GetNumNodes() const
unsigned mNodesPerElement
std::vector< double > GetNextNode()