Hermes2D  2.0
mesh_reader_h2d.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 <string.h>
17 #include "mesh.h"
18 #include <map>
19 #include <iostream>
20 #include "mesh_reader_h2d.h"
21 
22 namespace Hermes
23 {
24  namespace Hermes2D
25  {
26  extern unsigned g_mesh_seq;
27 
28  MeshReaderH2D::MeshReaderH2D()
29  {
30  }
31 
32  MeshReaderH2D::~MeshReaderH2D()
33  {
34  }
35 
36  Nurbs* MeshReaderH2D::load_nurbs(Mesh *mesh, MeshData *m, int id, Node** en, int &p1, int &p2)
37  {
38  double dummy_dbl;
39 
40  Nurbs* nurbs = new Nurbs;
41 
42  // Decide if curve is a circular arc or a general nurbs curve
43  bool circle = (m->curv_nurbs[id] == false);
44  nurbs->arc = circle;
45 
46  // read the end point indices
47  p1 = m->curv_first[id];
48  p2 = m->curv_second[id];
49 
50  *en = mesh->peek_edge_node(p1, p2);
51  if(*en == NULL)
52  throw Hermes::Exceptions::MeshLoadFailureException("Curve #%d: edge %d-%d does not exist.", id, p1, p2);
53 
54  // degree of curved edge
55  nurbs->degree = 2;
56  if(!circle)
57  {
58  nurbs->degree = m->curv_third[id];
59  }
60 
61  // get the number of control points
62  std::vector<double> vCP;
63 
64  int inner = 1, outer;
65  if(!circle)
66  {
67  for (unsigned int i = 0; i < m->vars_[m->curv_inner_pts[id]].size(); ++i)
68  {
69  std::istringstream istr(m->vars_[m->curv_inner_pts[id]][i]);
70 
71  if(!(istr >> dummy_dbl))
72  vCP.push_back(atof(m->vars_[m->vars_[m->curv_inner_pts[id]][i]][0].c_str()));
73  else
74  vCP.push_back(atof(m->vars_[m->curv_inner_pts[id]][i].c_str()));
75  }
76  inner = vCP.size()/3;
77  }
78  nurbs->np = inner + 2;
79 
80  // edge endpoints are also control points, with weight 1.0
81  nurbs->pt = new double3[nurbs->np];
82  nurbs->pt[0][0] = mesh->nodes[p1].x;
83  nurbs->pt[0][1] = mesh->nodes[p1].y;
84  nurbs->pt[0][2] = 1.0;
85  nurbs->pt[inner+1][0] = mesh->nodes[p2].x;
86  nurbs->pt[inner+1][1] = mesh->nodes[p2].y;
87  nurbs->pt[inner+1][2] = 1.0;
88 
89  if(!circle)
90  {
91  // read inner control points
92  for (int i = 0; i < inner; i++)
93  {
94  for (int j = 0; j < 3; ++j)
95  {
96  nurbs->pt[i + 1][j] = vCP[3*i + j];
97  }
98  }
99  }
100  else
101  {
102  // read the arc angle
103  nurbs->angle = m->curv_third[id];
104  double a = (180.0 - nurbs->angle) / 180.0 * M_PI;
105 
106  // generate one control point
107  double x = 1.0 / tan(a * 0.5);
108  nurbs->pt[1][0] = 0.5*((nurbs->pt[2][0] + nurbs->pt[0][0]) + (nurbs->pt[2][1] - nurbs->pt[0][1]) * x);
109  nurbs->pt[1][1] = 0.5*((nurbs->pt[2][1] + nurbs->pt[0][1]) - (nurbs->pt[2][0] - nurbs->pt[0][0]) * x);
110  nurbs->pt[1][2] = cos((M_PI - a) * 0.5);
111  }
112 
113  // get the number of knot vector points
114  std::vector<double> vKnots;
115 
116  inner = 0;
117  if(!circle)
118  {
119  for (unsigned int i = 0; i < m->vars_[m->curv_knots[id]].size(); ++i)
120  {
121  std::istringstream istr(m->vars_[m->curv_knots[id]][i]);
122 
123  if(!(istr >> dummy_dbl))
124  vKnots.push_back(atof(m->vars_[m->vars_[m->curv_knots[id]][i]][0].c_str()));
125  else
126  vKnots.push_back(atof(m->vars_[m->curv_knots[id]][i].c_str()));
127  }
128  inner = vKnots.size();
129  }
130 
131  nurbs->nk = nurbs->degree + nurbs->np + 1;
132  outer = nurbs->nk - inner;
133  if((outer & 1) == 1)
134  throw Hermes::Exceptions::MeshLoadFailureException("Curve #%d: incorrect number of knot points.", id);
135 
136  // knot vector is completed by 0.0 on the left and by 1.0 on the right
137  nurbs->kv = new double[nurbs->nk];
138 
139  for (int i = 0; i < outer/2; i++)
140  nurbs->kv[i] = 0.0;
141 
142  if(inner) {
143  for (int i = outer/2; i < inner + outer/2; i++) {
144  nurbs->kv[i] = vKnots[i - (outer/2)];
145  }
146  }
147 
148  for (int i = outer/2 + inner; i < nurbs->nk; i++)
149  nurbs->kv[i] = 1.0;
150 
151  nurbs->ref = 0;
152 
153  return nurbs;
154  }
155 
156  bool MeshReaderH2D::load(const char *filename, Mesh *mesh)
157  {
158  // Check if file exists
159  std::ifstream s(filename);
160  if(!s.good())
161  throw Hermes::Exceptions::MeshLoadFailureException("Mesh file not found.");
162  s.close();
163 
164  int i, j, k, n;
165  Node* en;
166  bool debug = false;
167 
168  mesh->free();
169 
170  std::string fName(filename);
171  MeshData m(fName);
172  m.parse_mesh();
173 
175 
176  n = m.n_vert;
177  if(n < 0) throw Hermes::Exceptions::MeshLoadFailureException("File %s: 'vertices' must be a list.", filename);
178  if(n < 2) throw Hermes::Exceptions::MeshLoadFailureException("File %s: invalid number of vertices.", filename);
179 
180  // create a hash table large enough
181  int size = HashTable::H2D_DEFAULT_HASH_SIZE;
182  while (size < 8*n) size *= 2;
183  mesh->init(size);
184 
185  // create top-level vertex nodes
186  for (i = 0; i < n; i++)
187  {
188  Node* node = mesh->nodes.add();
189  assert(node->id == i);
190  node->ref = TOP_LEVEL_REF;
191  node->type = HERMES_TYPE_VERTEX;
192  node->bnd = 0;
193  node->p1 = node->p2 = -1;
194  node->next_hash = NULL;
195  node->x = m.x_vertex[i];
196  node->y = m.y_vertex[i];
197  }
198  mesh->ntopvert = n;
199 
201 
202  n = m.n_el;
203  if(n < 0) throw Hermes::Exceptions::MeshLoadFailureException("File %s: 'elements' must be a list.", filename);
204  if(n < 1) throw Hermes::Exceptions::MeshLoadFailureException("File %s: no elements defined.", filename);
205 
206  // create elements
207  mesh->nactive = 0;
208  for (i = 0; i < n; i++)
209  {
210  // read and check vertex indices
211  int nv;
212  if(m.en4[i] == -1) nv = 4;
213  else nv = 5;
214 
215  int* idx = new int[nv-1];
216  std::string el_marker;
217  if(!nv) {
218  mesh->elements.skip_slot();
219  continue;
220  }
221 
222  if(nv < 4 || nv > 5)
223  {
224  delete [] idx;
225  throw Hermes::Exceptions::MeshLoadFailureException("File %s: element #%d: wrong number of vertex indices.", filename, i);
226  }
227 
228  if(nv == 4) {
229  idx[0] = m.en1[i];
230  idx[1] = m.en2[i];
231  idx[2] = m.en3[i];
232 
233  el_marker = m.e_mtl[i];
234  }
235  else {
236  idx[0] = m.en1[i];
237  idx[1] = m.en2[i];
238  idx[2] = m.en3[i];
239  idx[3] = m.en4[i];
240 
241  el_marker = m.e_mtl[i];
242  }
243  for (j = 0; j < nv-1; j++)
244  if(idx[j] < 0 || idx[j] >= mesh->ntopvert)
245  {
246  delete [] idx;
247  throw Hermes::Exceptions::MeshLoadFailureException("File %s: error creating element #%d: vertex #%d does not exist.", filename, i, idx[j]);
248  }
249 
250  Node *v0 = &mesh->nodes[idx[0]], *v1 = &mesh->nodes[idx[1]], *v2 = &mesh->nodes[idx[2]];
251 
252  int marker;
253 
254  // This functions check if the user-supplied marker on this element has been
255  // already used, and if not, inserts it in the appropriate structure.
256  mesh->element_markers_conversion.insert_marker(mesh->element_markers_conversion.min_marker_unused, el_marker);
257  marker = mesh->element_markers_conversion.get_internal_marker(el_marker).marker;
258 
259  if(nv == 4) {
260  Mesh::check_triangle(i, v0, v1, v2);
261  mesh->create_triangle(marker, v0, v1, v2, NULL);
262  }
263  else {
264  Node *v3 = &mesh->nodes[idx[3]];
265  Mesh::check_quad(i, v0, v1, v2, v3);
266  mesh->create_quad(marker, v0, v1, v2, v3, NULL);
267  }
268 
269  mesh->nactive++;
270 
271  delete [] idx;
272  }
273  mesh->nbase = n;
274 
276  if(m.n_bdy > 0)
277  {
278  n = m.n_bdy;
279 
280  // read boundary data
281  for (i = 0; i < n; i++)
282  {
283  int v1, v2, marker;
284  v1 = m.bdy_first[i];
285  v2 = m.bdy_second[i];
286 
287  en = mesh->peek_edge_node(v1, v2);
288  if(en == NULL)
289  throw Hermes::Exceptions::MeshLoadFailureException("File %s: boundary data #%d: edge %d-%d does not exist", filename, i, v1, v2);
290 
291  std::string bnd_marker;
292  bnd_marker = m.bdy_type[i];
293 
294  // This functions check if the user-supplied marker on this element has been
295  // already used, and if not, inserts it in the appropriate structure.
296  mesh->boundary_markers_conversion.insert_marker(mesh->boundary_markers_conversion.min_marker_unused, bnd_marker);
297  marker = mesh->boundary_markers_conversion.get_internal_marker(bnd_marker).marker;
298 
299  en->marker = marker;
300 
301  // This is extremely important, as in DG, it is assumed that negative boundary markers are reserved
302  // for the inner edges.
303  if(marker > 0)
304  {
305  mesh->nodes[v1].bnd = 1;
306  mesh->nodes[v2].bnd = 1;
307  en->bnd = 1;
308  }
309  }
310  }
311 
313  if(m.n_curv > 0)
314  {
315  n = m.n_curv;
316  if(n < 0) throw Hermes::Exceptions::MeshLoadFailureException("File %s: 'curves' must be a list.", filename);
317 
318  // load curved edges
319  for (i = 0; i < n; i++)
320  {
321  // load the control points, knot vector, etc.
322  Node* en;
323  int p1, p2;
324 
325  Nurbs* nurbs = load_nurbs(mesh, &m, i, &en, p1, p2);
326 
327  // assign the nurbs to the elements sharing the edge node
328  for (k = 0; k < 2; k++)
329  {
330  Element* e = en->elem[k];
331  if(e == NULL) continue;
332 
333  if(e->cm == NULL)
334  {
335  e->cm = new CurvMap;
336  memset(e->cm, 0, sizeof(CurvMap));
337  e->cm->toplevel = 1;
338  e->cm->order = 4;
339  }
340 
341  int idx = -1;
342  for (unsigned j = 0; j < e->get_nvert(); j++)
343  if(e->en[j] == en) { idx = j; break; }
344  assert(idx >= 0);
345 
346  if(e->vn[idx]->id == p1)
347  {
348  e->cm->nurbs[idx] = nurbs;
349  nurbs->ref++;
350  }
351  else
352  {
353  Nurbs* nurbs_rev = mesh->reverse_nurbs(nurbs);
354  e->cm->nurbs[idx] = nurbs_rev;
355  nurbs_rev->ref++;
356  }
357  }
358  if(!nurbs->ref) delete nurbs;
359  }
360  }
361 
362  // update refmap coeffs of curvilinear elements
363  Element* e;
364  for_all_elements(e, mesh)
365  if(e->cm != NULL)
366  e->cm->update_refmap_coeffs(e);
367 
369  if(m.n_ref > 0)
370  {
371  n = m.n_ref;
372  if(n < 0) throw Hermes::Exceptions::MeshLoadFailureException("File %s: 'refinements' must be a list.", filename);
373 
374  // perform initial refinements
375  for (i = 0; i < n; i++)
376  {
377  int id, ref;
378  id = m.ref_elt[i];
379  ref = m.ref_type[i];
380  mesh->refine_element_id(id, ref);
381  }
382  }
383  mesh->ninitial = mesh->elements.get_num_items();
384 
385  mesh->seq = g_mesh_seq++;
386  mesh->initial_single_check();
387  return true;
388  }
389 
390  void MeshReaderH2D::save_refinements(Mesh *mesh, FILE* f, Element* e, int id, bool& first)
391  {
392  if(e->active) return;
393  fprintf(f, first ? "refinements =\n{\n" : ",\n"); first = false;
394  if(e->bsplit())
395  {
396  fprintf(f, " { %d, 0 }", id);
397  int sid = mesh->seq; mesh->seq += 4;
398  for (int i = 0; i < 4; i++)
399  save_refinements(mesh, f, e->sons[i], sid+i, first);
400  }
401  else if(e->hsplit())
402  {
403  fprintf(f, " { %d, 1 }", id);
404  int sid = mesh->seq; mesh->seq += 2;
405  save_refinements(mesh, f, e->sons[0], sid, first);
406  save_refinements(mesh, f, e->sons[1], sid+1, first);
407  }
408  else
409  {
410  fprintf(f, " { %d, 2 }", id);
411  int sid = mesh->seq; mesh->seq += 2;
412  save_refinements(mesh, f, e->sons[2], sid, first);
413  save_refinements(mesh, f, e->sons[3], sid+1, first);
414  }
415  }
416 
417  void MeshReaderH2D::save_nurbs(Mesh *mesh, FILE* f, int p1, int p2, Nurbs* nurbs)
418  {
419  if(nurbs->arc)
420  {
421  fprintf(f, " [ %d, %d, %.16g ]", p1, p2, nurbs->angle);
422  }
423  else
424  {
425  int inner = nurbs->np - 2;
426  int outer = nurbs->nk - inner;
427  fprintf(f, " ú %d, %d, %d, ú ", p1, p2, nurbs->degree);
428  for (int i = 1; i < nurbs->np-1; i++)
429  fprintf(f, "ú %.16g, %.16g, %.16g ]%s ",
430  nurbs->pt[i][0], nurbs->pt[i][1], nurbs->pt[i][2],
431  i < nurbs->np-2 ? "," : "");
432 
433  fprintf(f, "],[ ");
434  int max = nurbs->nk - (nurbs->degree+1);
435  for (int i = nurbs->degree+1; i < max; i++)
436  fprintf(f, "%.16g%s", nurbs->kv[i], i < max-1 ? "," : "");
437  fprintf(f, "] ]");
438  }
439  }
440 
441  bool MeshReaderH2D::save(const char* filename, Mesh *mesh)
442  {
443  int i, mrk;
444  Element* e;
445 
446  // open output file
447  FILE* f = fopen(filename, "w");
448  if(f == NULL) throw Hermes::Exceptions::MeshLoadFailureException("Could not create mesh file.");
449  //fprintf(f, "# hermes2d saved mesh\n\n");
450 
451  // save vertices
452  fprintf(f, "vertices =\n[\n");
453  for (i = 0; i < mesh->ntopvert; i++)
454  fprintf(f, " [ %.16g, %.16g ]%s\n", mesh->nodes[i].x, mesh->nodes[i].y, (i < mesh->ntopvert-1 ? "," : ""));
455 
456  // save elements
457  fprintf(f, "]\n\nelements =\n[");
458  bool first = true;
459  for (i = 0; i < mesh->get_num_base_elements(); i++)
460  {
461  const char* nl = first ? "\n" : ",\n"; first = false;
462  e = mesh->get_element_fast(i);
463  if(!e->used)
464  fprintf(f, "%s [ ]", nl);
465  else if(e->is_triangle())
466  fprintf(f, "%s [ %d, %d, %d, \"%s\" ]", nl, e->vn[0]->id, e->vn[1]->id, e->vn[2]->id, mesh->get_element_markers_conversion().get_user_marker(e->marker).marker.c_str());
467  else
468  fprintf(f, "%s [ %d, %d, %d, %d, \"%s\" ]", nl, e->vn[0]->id, e->vn[1]->id, e->vn[2]->id, e->vn[3]->id, mesh->get_element_markers_conversion().get_user_marker(e->marker).marker.c_str());
469  }
470 
471  // save boundary markers
472  fprintf(f, "\n]\n\nboundaries =\n[");
473  first = true;
474  for_all_base_elements(e, mesh)
475  for (unsigned i = 0; i < e->get_nvert(); i++)
476  if((mrk = mesh->get_base_edge_node(e, i)->marker)) {
477  const char* nl = first ? "\n" : ",\n"; first = false;
478  fprintf(f, "%s [ %d, %d, \"%s\" ]", nl, e->vn[i]->id, e->vn[e->next_vert(i)]->id, mesh->boundary_markers_conversion.get_user_marker(mrk).marker.c_str());
479  }
480  fprintf(f, "\n]\n\n");
481 
482  // save curved edges
483  first = true;
484  for_all_base_elements(e, mesh)
485  if(e->is_curved())
486  for (unsigned i = 0; i < e->get_nvert(); i++)
487  if(e->cm->nurbs[i] != NULL && !is_twin_nurbs(e, i)) {
488  fprintf(f, first ? "curves =\n[\n" : ",\n"); first = false;
489  save_nurbs(mesh, f, e->vn[i]->id, e->vn[e->next_vert(i)]->id, e->cm->nurbs[i]);
490  }
491  if(!first) fprintf(f, "\n]\n\n");
492 
493  // save refinements
494  unsigned temp = mesh->seq;
495  mesh->seq = mesh->nbase;
496  first = true;
497  for_all_base_elements(e, mesh)
498  save_refinements(mesh, f, e, e->id, first);
499  if(!first) fprintf(f, "\n]\n\n");
500 
501  mesh->seq = temp;
502  fclose(f);
503 
504  return true;
505  }
506  }
507 }