Hermes2D  2.0
mesh_reader_exodusii.cpp
1 // This file is part of Hermes2D
2 //
3 // Hermes2D is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D; if not, see <http://www.gnu.prg/licenses/>.
15 
16 #include "config.h"
17 
18 #include <string.h>
19 #include "mesh_reader_exodusii.h"
20 #include "mesh.h"
21 #include <map>
22 
23 #ifdef WITH_EXODUSII
24 #include <exodusII.h>
25 #endif
26 namespace Hermes
27 {
28  namespace Hermes2D
29  {
30  MeshReaderExodusII::MeshReaderExodusII()
31  {
32 #ifdef WITH_EXODUSII
33 #else
34  throw Hermes::Exceptions::Exception("hermes2d was not compiled with ExodusII support");
35 #endif
36  }
37 
38  MeshReaderExodusII::~MeshReaderExodusII()
39  {
40  }
41 
42  struct Vertex
43  {
44  double x, y;
45  };
46 
47  // needed for comparison of vertices inside std::map
48  struct VCompare
49  {
50  bool operator()(Vertex a, Vertex b) const
51  {
52  if(a.x < b.x) return true;
53  else if(a.x > b.x) return false;
54  else
55  {
56  if(a.y < b.y) return true;
57  return false;
58  }
59  }
60  };
61 
62  bool MeshReaderExodusII::load(const char *file_name, Mesh *mesh)
63  {
64 #ifdef WITH_EXODUSII
65  int err;
66  int cpu_ws = sizeof(double); // use float or double
67  int io_ws = 8; // store variables as doubles
68  float version;
69  int exoid = ex_open(file_name, EX_READ, &cpu_ws, &io_ws, &version);
70 
71  // read initialization parameters
72  int n_dims, n_nodes, n_elems, n_eblocks, n_nodesets, n_sidesets;
73  char title[MAX_LINE_LENGTH + 1];
74  err = ex_get_init(exoid, title, &n_dims, &n_nodes, &n_elems, &n_eblocks, &n_nodesets, &n_sidesets);
75  if(n_dims != 2)
76  {
77  throw Hermes::Exceptions::Exception("File '%s' does not contain 2D mesh", file_name);
78  return false;
79  }
80 
81  // load coordinates
82  double *x = new double[n_nodes];
83  double *y = new double[n_nodes];
84  err = ex_get_coord(exoid, x, y, NULL);
85 
86  // remove duplicate vertices and build renumbering map
87  std::map<Vertex, int, VCompare> vtx_list; // map for eliminating duplicities
88  std::map<int, int> vmap; // reindexing map
89  Hermes::vector<Vertex> vtx_arr; // vertex array
90  int vid = 0;
91  for (int i = 0; i < n_nodes; i++)
92  {
93  int k;
94  Vertex v = { x[i], y[i] };
95  if(vtx_list.count(v) == 0)
96  {
97  vtx_arr.push_back(v);
98  k = vid++;
99  vtx_list[v] = k;
100  }
101  else
102  k = vtx_list[v];
103 
104  vmap[i + 1] = k;
105  }
106  delete [] x;
107  delete [] y;
108 
109  int n_vtx = vtx_arr.size();
110  double2 *vtx = new double2[n_vtx];
111  for (int i = 0; i < n_vtx; i++)
112  {
113  vtx[i][0] = vtx_arr[i].x;
114  vtx[i][1] = vtx_arr[i].y;
115  }
116 
117  int n_tri = 0; // number of triangles
118  int n_quad = 0; // number of quads
119 
120  // get info about element blocks
121  int *eid_blocks = new int[n_eblocks];
122  err = ex_get_elem_blk_ids(exoid, eid_blocks);
123  // go over all element blocks
124  for (int i = 0; i < n_eblocks; i++)
125  {
126  int id = eid_blocks[i];
127 
128  // get block info
129  char elem_type[MAX_STR_LENGTH + 1];
130  int n_elems_in_blk, n_elem_nodes, n_attrs;
131  err = ex_get_elem_block(exoid, id, elem_type, &n_elems_in_blk, &n_elem_nodes, &n_attrs);
132 
133  if(n_elem_nodes == 3) n_tri += n_elems_in_blk;
134  else if(n_elem_nodes == 4) n_quad += n_elems_in_blk;
135  else
136  {
137  delete [] vtx;
138  throw Hermes::Exceptions::Exception("Unknown type of element");
139  return false;
140  }
141  }
142  int3 *tri = n_tri > 0 ? new int3[n_tri] : NULL; // triangles
143  std::string *tri_markers = n_tri > 0 ? new std::string[n_tri] : NULL;
144  int4 *quad = n_quad > 0 ? new int4[n_quad] : NULL; // quads
145  std::string *quad_markers = n_quad > 0 ? new std::string[n_quad] : NULL;
146 
147  int n_els = n_tri + n_quad; // total number of elements
148  int **els = n_els > 0 ? new int *[n_els] : NULL; // elements
149  int *el_nv = n_els > 0 ? new int[n_els] : NULL; // number of vertices for each element
150 
151  int it = 0, iq = 0, iel = 0;
152  for (int i = 0; i < n_eblocks; i++)
153  {
154  int id = eid_blocks[i];
155 
156  // get block info
157  char elem_type[MAX_STR_LENGTH + 1];
158  int n_elems_in_blk, n_elem_nodes, n_attrs;
159  err = ex_get_elem_block(exoid, id, elem_type, &n_elems_in_blk, &n_elem_nodes, &n_attrs);
160 
161  // read connectivity array
162  int *connect = new int[n_elem_nodes * n_elems_in_blk];
163  err = ex_get_elem_conn(exoid, id, connect);
164 
165  // Update the mesh' internal array element_markers_conversion.
166  std::ostringstream string_stream;
167  string_stream << id;
168  std::string el_marker = string_stream.str();
169 
170  // This functions check if the user-supplied marker on this element has been
171  // already used, and if not, inserts it in the appropriate structure.
172  mesh->element_markers_conversion.insert_marker(mesh->element_markers_conversion.min_marker_unused, el_marker);
173 
174  int ic = 0;
175  for (int j = 0; j < n_elems_in_blk; j++)
176  {
177  el_nv[iel] = n_elem_nodes;
178  if(n_elem_nodes == 3)
179  {
180  tri[it][0] = vmap[connect[ic++]];
181  tri[it][1] = vmap[connect[ic++]];
182  tri[it][2] = vmap[connect[ic++]];
183  tri_markers[it] = el_marker;
184  els[iel] = tri[it];
185  it++;
186  }
187  else if(n_elem_nodes == 4)
188  {
189  quad[iq][0] = vmap[connect[ic++]];
190  quad[iq][1] = vmap[connect[ic++]];
191  quad[iq][2] = vmap[connect[ic++]];
192  quad[iq][3] = vmap[connect[ic++]];
193  quad_markers[iq] = el_marker;
194  els[iel] = quad[iq];
195  iq++;
196  }
197  else
198  {
199  delete [] vtx;
200  throw Hermes::Exceptions::Exception("Unknown type of element");
201  return false;
202  }
203  iel++;
204  }
205  delete [] connect;
206  }
207  delete [] eid_blocks;
208 
209  // query number of side sets
210  int *sid_blocks = new int[n_sidesets];
211  err = ex_get_side_set_ids(exoid, sid_blocks);
212 
213  // go over the sidesets
214  int n_mark = 0; // number of markers
215  for (int i = 0; i < n_sidesets; i++)
216  {
217  int sid = sid_blocks[i];
218  int n_sides_in_set, n_df_in_set;
219  err = ex_get_side_set_param(exoid, sid, &n_sides_in_set, &n_df_in_set);
220  n_mark += n_sides_in_set;
221  }
222  int2 *marks = new int2[n_mark];
223  std::string *bnd_markers = new std::string[n_mark];
224 
225  int im = 0;
226  for (int i = 0; i < n_sidesets; i++)
227  {
228  int sid = sid_blocks[i];
229  int n_sides_in_set, n_df_in_set;
230  err = ex_get_side_set_param(exoid, sid, &n_sides_in_set, &n_df_in_set);
231  int num_elem_in_set = n_sides_in_set;
232 
233  int *elem_list = new int[num_elem_in_set];
234  int *side_list = new int[n_sides_in_set];
235  err = ex_get_side_set(exoid, sid, elem_list, side_list);
236 
237  // Update the mesh' internal array boundary_markers_conversion.
238  std::ostringstream string_stream;
239  string_stream << sid;
240  std::string bnd_marker = string_stream.str();
241 
242  // This functions check if the user-supplied marker on this element has been
243  // already used, and if not, inserts it in the appropriate structure.
244  mesh->boundary_markers_conversion.insert_marker(mesh->boundary_markers_conversion.min_marker_unused, bnd_marker);
245 
246  for (int j = 0; j < num_elem_in_set; j++)
247  {
248  int nv = el_nv[side_list[j] - 1]; // # of vertices of the element
249  int vt = side_list[j] - 1;
250  marks[im][0] = els[elem_list[j] - 1][vt];
251  marks[im][1] = els[elem_list[j] - 1][(vt + 1) % nv];
252  bnd_markers[im] = bnd_marker;
253  im++;
254  }
255 
256  delete [] elem_list;
257  delete [] side_list;
258  }
259  delete [] sid_blocks;
260 
261  // we are done
262  err = ex_close(exoid);
263 
264  mesh->create(n_vtx, vtx, n_tri, tri, tri_markers, n_quad, quad, quad_markers, n_mark, marks, bnd_markers);
265 
266  // clean-up
267  delete [] marks;
268  delete [] tri;
269  delete [] quad;
270  delete [] tri_markers;
271  delete [] quad_markers;
272  delete [] bnd_markers;
273  delete [] vtx;
274  delete [] el_nv;
275  delete [] els;
276 
277  return true;
278 #else
279  return false;
280 #endif
281  }
282  }
283 }