Flow123d  master-c754b67
msh_gmshreader.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file msh_gmshreader.cc
15  * @ingroup mesh
16  * @brief
17  * @author dalibor
18  */
19 
20 #include <istream>
21 #include <string>
22 #include <limits>
23 
24 #include "msh_gmshreader.h"
26 
27 #include "system/system.hh"
28 #include "system/tokenizer.hh"
29 #include "boost/lexical_cast.hpp"
30 
31 #include "mesh/mesh.h"
32 #include "mesh/bc_mesh.hh"
33 
34 
35 
36 using namespace std;
37 
38 
40 : BaseMeshReader(file_name)
41 {
42  tok_.set_comment_pattern( "#");
43  data_section_name_ = "$ElementData";
44  has_compatible_mesh_ = false;
46 }
47 
48 
49 
50 GmshMeshReader::~GmshMeshReader() // Tokenizer close the file automatically
51 {}
52 
53 
54 
56  using namespace boost;
57  unsigned int n_nodes;
58  MessageOut() << "- Reading nodes...";
59  tok_.set_position( Tokenizer::Position() );
60 
61  if (! tok_.skip_to("$Nodes")) THROW(ExcMissingSection() << EI_Section("$Nodes") << EI_GMSHFile(tok_.f_name()) );
62  try {
63  tok_.next_line(false);
64  n_nodes = lexical_cast<unsigned int> (*tok_);
65  mesh->init_node_vector( n_nodes );
66  if (n_nodes == 0) THROW( ExcZeroNodes() << EI_Position(tok_.position_msg()) );
67  ++tok_; // end of line
68 
69  for (unsigned int i = 0; i < n_nodes; ++i) {
70  tok_.next_line();
71 
72  unsigned int id = lexical_cast<unsigned int> (*tok_); ++tok_; // node id
73  arma::vec3 coords; // node coordinates
74  coords(0) = lexical_cast<double> (*tok_); ++tok_;
75  coords(1) = lexical_cast<double> (*tok_); ++tok_;
76  coords(2) = lexical_cast<double> (*tok_); ++tok_;
77  ++tok_; // skip mesh size parameter
78 
79  mesh->add_node(id, coords);
80  }
81 
82  } catch (bad_lexical_cast &) {
83  THROW(ExcWrongFormat() << EI_Type("number") << EI_TokenizerMsg(tok_.position_msg()) << EI_MeshFile(tok_.f_name()) );
84  }
85  MessageOut().fmt("... {} nodes read. \n", n_nodes);
86 }
87 
88 
90  using namespace boost;
91  MessageOut() << "- Reading elements...";
92 
93  if (! tok_.skip_to("$Elements")) THROW(ExcMissingSection() << EI_Section("$Elements") << EI_GMSHFile(tok_.f_name()) );
94  try {
95  tok_.next_line(false);
96  unsigned int n_elements = lexical_cast<unsigned int> (*tok_);
97  if (n_elements == 0) THROW( ExcZeroElements() << EI_Position(tok_.position_msg()) );
98  ++tok_; // end of line
99 
100  std::vector<unsigned int> node_ids; //node_ids of elements
101  node_ids.resize(4); // maximal count of nodes
102 
103  mesh->init_element_vector(n_elements);
104 
105  for (unsigned int i = 0; i < n_elements; ++i) {
106  tok_.next_line();
107  unsigned int id = lexical_cast<unsigned int>(*tok_); ++tok_;
108 
109  //get element type: supported:
110  // 1 Line (2 nodes)
111  // 2 Triangle (3 nodes)
112  // 4 Tetrahedron (4 nodes)
113  // 15 Point (1 node)
114  unsigned int type = lexical_cast<unsigned int>(*tok_); ++tok_;
115  unsigned int dim;
116  switch (type) {
117  case 1:
118  dim = 1;
119  break;
120  case 2:
121  dim = 2;
122  break;
123  case 4:
124  dim = 3;
125  break;
126  case 15:
127  dim = 0;
128  break;
129  default:
130  dim = 0;
131  THROW(ExcUnsupportedType() << EI_ElementId(id) << EI_ElementType(type) << EI_GMSHFile(tok_.f_name()) );
132  break;
133  }
134 
135  //get number of tags (at least 2)
136  unsigned int n_tags = lexical_cast<unsigned int>(*tok_);
137  if (n_tags < 2) THROW( ExcTooManyElementTags() << EI_ElementId(id) << EI_Position(tok_.position_msg()) );
138  ++tok_;
139 
140  //get tags 1 and 2
141  unsigned int region_id = lexical_cast<unsigned int>(*tok_); ++tok_; // region_id
142  lexical_cast<unsigned int>(*tok_); ++tok_; // GMSH region number, we do not store this
143  //get remaining tags
144  unsigned int partition_id = 0;
145  if (n_tags > 2) { partition_id = lexical_cast<unsigned int>(*tok_); ++tok_; } // save partition number from the new GMSH format
146  for (unsigned int ti = 3; ti < n_tags; ti++) ++tok_; //skip remaining tags
147 
148  for (unsigned int ni=0; ni<dim+1; ++ni) { // read node ids
149  node_ids[ni] = lexical_cast<unsigned int>(*tok_);
150  ++tok_;
151  }
152  mesh->add_element(id, dim, region_id, partition_id, node_ids);
153  }
154 
155  } catch (bad_lexical_cast &) {
156  THROW(ExcWrongFormat() << EI_Type("number") << EI_TokenizerMsg(tok_.position_msg()) << EI_MeshFile(tok_.f_name()) );
157  }
158 
159  MessageOut().fmt("... {} bulk elements, {} boundary elements. \n", mesh->n_elements(), mesh->bc_mesh()->n_elements());
160 }
161 
162 
163 
165  ASSERT_PTR(mesh).error("Argument mesh is NULL.\n");
166 
167  using namespace boost;
168 
169  if (! tok_.skip_to("$PhysicalNames", "$Nodes") ) return;
170  try {
171  tok_.next_line(false);
172  unsigned int n_physicals = lexical_cast<unsigned int> (*tok_);
173  ++tok_; // end of line
174 
175  for (unsigned int i = 0; i < n_physicals; ++i) {
176  tok_.next_line();
177  // format of one line:
178  // dim physical-id physical-name
179 
180  unsigned int dim = lexical_cast<unsigned int>(*tok_); ++tok_;
181  unsigned int id = lexical_cast<unsigned int>(*tok_); ++tok_;
182  string name = *tok_; ++tok_;
183  mesh->add_physical_name( dim, id, name );
184  }
185 
186  } catch (bad_lexical_cast &) {
187  THROW(ExcWrongFormat() << EI_Type("number") << EI_TokenizerMsg(tok_.position_msg()) << EI_MeshFile(tok_.f_name()) );
188  }
189 
190 }
191 
192 
193 // Is assumed to be called just after tok.skip_to("..")
194 // reads the header from the tokenizer @p tok and return it as the second parameter
196  using namespace boost;
197  try {
198  // string tags
199  tok_.next_line(false);
200  unsigned int n_str = lexical_cast<unsigned int>(*tok_); ++tok_;
201  head.field_name="";
202  head.interpolation_scheme = "";
203  if (n_str > 0) {
204  tok_.next_line(); n_str--;
205  head.field_name= *tok_; ++tok_; // unquoted by tokenizer if needed
206  }
207  if (n_str > 0) {
208  tok_.next_line(); n_str--;
209  head.interpolation_scheme = *tok_; ++tok_;
210  }
211  for(;n_str>0;n_str--) tok_.next_line(false); // skip possible remaining tags
212 
213  //real tags
214  tok_.next_line();
215  unsigned int n_real = lexical_cast<unsigned int>(*tok_); ++tok_;
216  head.time=0.0;
217  if (n_real>0) {
218  tok_.next_line(); n_real--;
219  head.time=lexical_cast<double>(*tok_); ++tok_;
220  }
221  for(;n_real>0;n_real--) tok_.next_line(false);
222 
223  // int tags
224  tok_.next_line();
225  unsigned int n_int = lexical_cast<unsigned int>(*tok_); ++tok_;
226  head.time_index=0;
227  head.n_components=1;
228  head.n_entities=0;
229  head.partition_index=0;
230  if (n_int>0) {
231  tok_.next_line(); n_int--;
232  head.time_index=lexical_cast<unsigned int>(*tok_); ++tok_;
233  }
234  if (n_int>0) {
235  tok_.next_line(); n_int--;
236  head.n_components=lexical_cast<unsigned int>(*tok_); ++tok_;
237  }
238  if (n_int>0) {
239  tok_.next_line(); n_int--;
240  head.n_entities=lexical_cast<unsigned int>(*tok_); ++tok_;
241  }
242  for(;n_int>0;n_int--) tok_.next_line(false);
243  head.position = tok_.get_position();
244  head.discretization = OutputTime::DiscreteSpace::ELEM_DATA;
245  } catch (bad_lexical_cast &) {
246  THROW(ExcWrongFormat() << EI_Type("$ElementData header") << EI_TokenizerMsg(tok_.position_msg()) << EI_MeshFile(tok_.f_name()) );
247  }
248 }
249 
250 
251 
253  static int imax = std::numeric_limits<int>::max();
254  unsigned int id, i_row;
255  unsigned int n_bulk_read = 0, n_bdr_read = 0;
256  std::vector<int> bulk_el_ids = this->get_element_ids(false); // bulk
257  bulk_el_ids.push_back( imax ); // put 'save' item at the end of vector
258  vector<int>::const_iterator bulk_id_iter = bulk_el_ids.begin();
259  std::vector<int> bdr_el_ids = this->get_element_ids(true); // boundary
260  bdr_el_ids.push_back( imax ); // put 'save' item at the end of vector
261  vector<int>::const_iterator bdr_id_iter = bdr_el_ids.begin();
262 
263  // read @p data buffer as we have correct header with already passed time
264  // we assume that @p data buffer is big enough
265  tok_.set_position(header.position);
266 
267  // read data
268  for (i_row = 0; i_row < header.n_entities; ++i_row)
269  try {
270  tok_.next_line();
271  id = boost::lexical_cast<unsigned int>(*tok_); ++tok_;
272 
273  while ( std::min(*bulk_id_iter, *bdr_id_iter) < (int)id) { // skip initialization of some rows in data if ID is missing
274  if (*bulk_id_iter < *bdr_id_iter) ++bulk_id_iter;
275  else ++bdr_id_iter;
276  }
277 
278  if (*bulk_id_iter == (int)id) {
279  // bulk
280  data_cache.read_ascii_data(tok_, header.n_components, (bulk_id_iter - bulk_el_ids.begin()) );
281  ++n_bulk_read; ++bulk_id_iter;
282  } else if (*bdr_id_iter == (int)id) {
283  // boundary
284  unsigned int bdr_shift = data_cache.get_boundary_begin();
285  data_cache.read_ascii_data(tok_, header.n_components, (bdr_id_iter - bdr_el_ids.begin() + bdr_shift) );
286  ++n_bdr_read; ++bdr_id_iter;
287  } else {
288  if ( (*bulk_id_iter != imax) | (*bdr_id_iter != imax) )
289  WarningOut().fmt("In file '{}', '$ElementData' section for field '{}', time: {}.\nData ID {} is not in order. Skipping rest of data.\n",
290  tok_.f_name(), header.field_name, header.time, id);
291  break;
292  }
293 
294  } catch (boost::bad_lexical_cast &) {
295  THROW(ExcWrongFormat() << EI_Type("$ElementData line") << EI_TokenizerMsg(tok_.position_msg())
296  << EI_MeshFile(tok_.f_name()) );
297  }
298  // possibly skip remaining lines after break
299  while (i_row < header.n_entities) tok_.next_line(false), ++i_row;
300 
301  LogOut().fmt("time: {}; {} bulk and {} boundary entities of field {} read.\n",
302  header.time, n_bulk_read, n_bdr_read, header.field_name);
303 }
304 
305 
306 
308 {
309  header_table_.clear();
310  MeshDataHeader header;
311  while ( !tok_.eof() ) {
312  if ( tok_.skip_to("$ElementData") ) {
313  read_data_header(header);
314  HeaderTable::iterator it = header_table_.find(header.field_name);
315 
316  if (it == header_table_.end()) { // field doesn't exists, insert new vector to map
318  vec.push_back(header);
319  header_table_[header.field_name]=vec;
320  } else if ( header.time <= it->second.back().time ) { // time is in wrong order. can't be add
321  WarningOut().fmt("Wrong time order: field '{}', time '{}', file '{}'. Skipping this '$ElementData' section.\n",
322  header.field_name, header.time, tok_.f_name() );
323  } else { // add new time step
324  it->second.push_back(header);
325  }
326  }
327  }
328 
329  tok_.set_position( Tokenizer::Position() );
330 }
331 
332 
333 
335 {
336  // check discretization, only type element_data or undefined is supported
337  if (header_query.discretization != OutputTime::DiscreteSpace::ELEM_DATA) {
338  if (header_query.discretization != OutputTime::DiscreteSpace::UNDEFINED && header_query.discretization != OutputTime::DiscreteSpace::NATIVE_DATA) {
339  WarningOut().fmt(
340  "Unsupported discretization for field '{}', time: {} and GMSH format.\nType 'ELEM_DATA' of discretization will be used.\n",
341  header_query.field_name, header_query.time);
342  }
343  header_query.discretization = OutputTime::DiscreteSpace::ELEM_DATA;
344  }
345 
346  HeaderTable::iterator table_it = header_table_.find(header_query.field_name);
347 
348  if (table_it == header_table_.end()) {
349  // no data found
350  THROW( ExcFieldNameNotFound() << EI_FieldName(header_query.field_name) << EI_MeshFile(tok_.f_name()));
351  }
352 
353  auto comp = [](double t, const MeshDataHeader &a) {
354  return t * (1.0 + 2.0*numeric_limits<double>::epsilon()) < a.time;
355  };
356 
357  std::vector<MeshDataHeader>::iterator headers_it = std::upper_bound(table_it->second.begin(),
358  table_it->second.end(),
359  header_query.time,
360  comp);
361 
362  if (headers_it == table_it->second.begin()) {
363  THROW( ExcFieldNameNotFound() << EI_FieldName(header_query.field_name)
364  << EI_MeshFile(tok_.f_name()) << EI_Time(header_query.time));
365  }
366 
367  --headers_it;
368  return *headers_it;
369 }
BaseMeshReader::tok_
Tokenizer tok_
Tokenizer used for reading ASCII file format.
Definition: msh_basereader.hh:257
Armor::vec
ArmaVec< double, N > vec
Definition: armor.hh:885
element_data_cache_base.hh
GmshMeshReader::find_header
MeshDataHeader & find_header(HeaderQuery &header_query) override
Definition: msh_gmshreader.cc:334
GmshMeshReader::make_header_table
void make_header_table() override
Definition: msh_gmshreader.cc:307
bc_mesh.hh
ElementDataCacheBase::get_boundary_begin
unsigned int get_boundary_begin() const
Returns start position of boundary data in cache.
Definition: element_data_cache_base.hh:227
GmshMeshReader::read_physical_names
void read_physical_names(Mesh *mesh) override
Definition: msh_gmshreader.cc:164
FilePath
Dedicated class for storing path to input and output files.
Definition: file_path.hh:54
THROW
#define THROW(whole_exception_expr)
Wrapper for throw. Saves the throwing point.
Definition: exceptions.hh:53
std::vector< unsigned int >
boost
Definition: finite_state_filter.hpp:34
system.hh
arma::vec3
Definition: doxy_dummy_defs.hh:17
BaseMeshReader::MeshDataHeader::interpolation_scheme
std::string interpolation_scheme
Currently d'ont used.
Definition: msh_basereader.hh:127
BaseMeshReader::MeshDataHeader::n_components
unsigned int n_components
Number of values on one row.
Definition: msh_basereader.hh:133
msh_gmshreader.h
GmshMeshReader::read_element_data
void read_element_data(ElementDataCacheBase &data_cache, MeshDataHeader header) override
Definition: msh_gmshreader.cc:252
BaseMeshReader::MeshDataHeader::discretization
OutputTime::DiscreteSpace discretization
Flag marks input discretization of data of VTK file.
Definition: msh_basereader.hh:143
Mesh::bc_mesh
BCMesh * bc_mesh() const override
Implement MeshBase::bc_mesh(), getter of boundary mesh.
Definition: mesh.h:567
BaseMeshReader::HeaderQuery::field_name
std::string field_name
Name of field.
Definition: msh_basereader.hh:139
BaseMeshReader
Definition: msh_basereader.hh:58
LogOut
#define LogOut()
Macro defining 'log' record of log.
Definition: logger.hh:281
BaseMeshReader::MeshDataHeader::field_name
std::string field_name
Name of field.
Definition: msh_basereader.hh:125
BaseMeshReader::get_element_ids
const std::vector< int > & get_element_ids(bool boundary_domain)
Definition: msh_basereader.cc:88
GmshMeshReader::read_nodes
void read_nodes(Mesh *mesh)
Definition: msh_gmshreader.cc:55
ElementDataCacheBase
Definition: element_data_cache_base.hh:33
mesh.h
Mesh::add_element
void add_element(unsigned int elm_id, unsigned int dim, unsigned int region_id, unsigned int partition_id, std::vector< unsigned int > node_ids)
Add new element of given id to mesh.
Definition: mesh.cc:1094
Input::Type
Definition: balance.hh:41
BaseMeshReader::MeshDataHeader
Definition: msh_basereader.hh:104
MeshBase::init_node_vector
void init_node_vector(unsigned int size)
Initialize node_vec_, set size.
Definition: mesh.cc:1152
GmshMeshReader::~GmshMeshReader
virtual ~GmshMeshReader()
Definition: msh_gmshreader.cc:50
ElementDataCacheBase::read_ascii_data
virtual void read_ascii_data(Tokenizer &tok, unsigned int n_components, unsigned int i_row)=0
Mesh
Definition: mesh.h:362
MeshBase::init_element_vector
void init_element_vector(unsigned int size)
Initialize element_vec_, set size and reset counters of boundary and bulk elements.
Definition: mesh.cc:1142
BaseMeshReader::HeaderQuery::discretization
OutputTime::DiscreteSpace discretization
Flag determinate type of discrete of Field (typically is used for native data of VTK)
Definition: msh_basereader.hh:143
WarningOut
#define WarningOut()
Macro defining 'warning' record of log.
Definition: logger.hh:278
BaseMeshReader::MeshDataHeader::partition_index
unsigned int partition_index
Currently d'ont used.
Definition: msh_basereader.hh:137
std
Definition: doxy_dummy_defs.hh:5
BaseMeshReader::MeshDataHeader::position
Tokenizer::Position position
Position of data in mesh file.
Definition: msh_basereader.hh:139
Mesh::add_node
void add_node(unsigned int node_id, arma::vec3 coords)
Add new node of given id and coordinates to mesh.
Definition: mesh.cc:1086
BaseMeshReader::MeshDataHeader::n_entities
unsigned int n_entities
Number of rows.
Definition: msh_basereader.hh:135
BaseMeshReader::MeshDataHeader::time_index
unsigned int time_index
Currently d'ont used.
Definition: msh_basereader.hh:131
GmshMeshReader::header_table_
HeaderTable header_table_
Table with data of ElementData headers.
Definition: msh_gmshreader.h:115
MeshBase::n_elements
unsigned int n_elements() const
Definition: mesh.h:111
BaseMeshReader::data_section_name_
std::string data_section_name_
Store name of field data section specify for type of mesh file.
Definition: msh_basereader.hh:251
GmshMeshReader::read_data_header
void read_data_header(MeshDataHeader &head)
Definition: msh_gmshreader.cc:195
BaseMeshReader::MeshDataHeader::time
double time
Time of field data (used only for GMSH reader)
Definition: msh_basereader.hh:129
ASSERT_PTR
#define ASSERT_PTR(ptr)
Definition of assert macro checking non-null pointer (PTR) only for debug mode.
Definition: asserts.hh:341
BaseMeshReader::HeaderQuery::time
double time
Time of field data (used only for GMSH and PVD reader)
Definition: msh_basereader.hh:142
BaseMeshReader::has_compatible_mesh_
bool has_compatible_mesh_
Definition: msh_basereader.hh:248
BaseMeshReader::HeaderQuery
Definition: msh_basereader.hh:136
Mesh::add_physical_name
void add_physical_name(unsigned int dim, unsigned int id, std::string name)
Add new node of given id and coordinates to mesh.
Definition: mesh.cc:1081
tokenizer.hh
MessageOut
#define MessageOut()
Macro defining 'message' record of log.
Definition: logger.hh:275
GmshMeshReader::GmshMeshReader
GmshMeshReader(const FilePath &file_name)
Definition: msh_gmshreader.cc:39
GmshMeshReader::read_elements
void read_elements(Mesh *mesh)
Definition: msh_gmshreader.cc:89