Hermes2D  3.0
mesh.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.org/licenses/>.
15 
16 #include "mesh_util.h"
17 #include "refmap.h"
18 #include "global.h"
19 #include "api2d.h"
20 #include "mesh_reader_h2d.h"
21 #include "neighbor_search.h"
22 #include "mixins.h"
23 #include "forms.h"
24 
25 namespace Hermes
26 {
27  namespace Hermes2D
28  {
29  unsigned g_mesh_seq = 0;
30  static const int H2D_DG_INNER_EDGE_INT = -54125631;
31  static const std::string H2D_DG_INNER_EDGE = "-54125631";
32 
33  Mesh::Mesh() : HashTable(), meshHashGrid(nullptr), nbase(0), nactive(0), ntopvert(0), ninitial(0), seq(g_mesh_seq++),
34  bounding_box_calculated(0)
35  {
36  }
37 
38  Mesh::~Mesh()
39  {
40  free();
41  }
42 
43  bool Mesh::isOkay() const
44  {
45  bool okay = true;
46 
47  if (this->elements.get_size() < 1)
48  okay = false;
49  if (this->nodes.get_size() < 1)
50  okay = false;
51  if (seq < 0)
52  okay = false;
53  return okay;
54  }
55 
56  Mesh::ReferenceMeshCreator::ReferenceMeshCreator(MeshSharedPtr coarse_mesh, int refinement) : coarse_mesh(coarse_mesh), refinement(refinement)
57  {
58  }
59 
61  {
62  Mesh* ref_mesh = new Mesh;
63  ref_mesh->copy(this->coarse_mesh);
64  ref_mesh->refine_all_elements(refinement, false);
65  return MeshSharedPtr(ref_mesh);
66  }
67 
69  {
70  RefMap r;
71  Element* e;
72  Quad2D* quad = &g_quad_2d_std;
73  for_all_active_elements(e, this)
74  {
75  r.set_active_element(e);
76 
77  int i, mo = quad->get_max_order(e->get_mode());
78 
79  int k = e->is_triangle() ? 2 : 3;
80 
81  double const_m[2][2] =
82  {
83  { e->vn[1]->x - e->vn[0]->x, e->vn[k]->x - e->vn[0]->x },
84  { e->vn[1]->y - e->vn[0]->y, e->vn[k]->y - e->vn[0]->y }
85  };
86 
87  double const_jacobian = 0.25 * (const_m[0][0] * const_m[1][1] - const_m[0][1] * const_m[1][0]);
88  if (const_jacobian <= 0.0)
89  throw Hermes::Exceptions::MeshLoadFailureException("Element #%d is concave or badly oriented in initial_single_check().", e->id);
90 
91  // check first the positivity of the jacobian
92  double3* pt = quad->get_points(mo, e->get_mode());
93  if (!r.is_jacobian_const())
94  {
95  double2x2* m = r.get_inv_ref_map(mo);
96  double* jac = r.get_jacobian(mo);
97  for (i = 0; i < quad->get_num_points(mo, e->get_mode()); i++)
98  if (jac[i] <= 0.0)
99  throw Hermes::Exceptions::MeshLoadFailureException("Element #%d is concave or badly oriented in initial_single_check().", e->id);
100  }
101  }
102  }
103 
104  void Mesh::create(int nv, double2* verts, int nt, int3* tris, std::string* tri_markers,
105  int nq, int4* quads, std::string* quad_markers, int nm, int2* mark, std::string* boundary_markers)
106  {
107  free();
108 
109  // initialize hash table
110  int size = 16;
111  while (size < 2 * nv) size *= 2;
112  init(size);
113 
114  // create vertex nodes
115  for (int i = 0; i < nv; i++)
116  {
117  Node* node = nodes.add();
118  assert(node->id == i);
119  node->ref = TOP_LEVEL_REF;
120  node->type = HERMES_TYPE_VERTEX;
121  node->bnd = 0;
122  node->p1 = node->p2 = -1;
123  node->next_hash = nullptr;
124  node->x = verts[i][0];
125  node->y = verts[i][1];
126  }
127  ntopvert = nv;
128 
129  // create triangles
130  Element* e;
131  for (int i = 0; i < nt; i++)
132  {
133  e = create_triangle(this->element_markers_conversion.insert_marker(tri_markers[i]), &nodes[tris[i][0]], &nodes[tris[i][1]],
134  &nodes[tris[i][2]], nullptr);
135  }
136 
137  // create quads
138  for (int i = 0; i < nq; i++)
139  {
140  e = create_quad(this->element_markers_conversion.insert_marker(quad_markers[i]), &nodes[quads[i][0]], &nodes[quads[i][1]],
141  &nodes[quads[i][2]], &nodes[quads[i][3]], nullptr);
142  }
143 
144  // set boundary markers
145  for (int i = 0; i < nm; i++)
146  {
147  Node* en = peek_edge_node(mark[i][0], mark[i][1]);
148  if (en == nullptr)
149  throw Hermes::Exceptions::Exception("Boundary data error (edge does not exist)");
150 
151  en->marker = this->boundary_markers_conversion.insert_marker(boundary_markers[i]);
152 
153  nodes[mark[i][0]].bnd = 1;
154  nodes[mark[i][1]].bnd = 1;
155  en->bnd = 1;
156  }
157 
158  nbase = nactive = ninitial = nt + nq;
159  seq = g_mesh_seq++;
160  }
161 
163  {
164  if (this == nullptr) throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_elements().");
165  if (this->seq < 0)
166  return -1;
167  else
168  return elements.get_num_items();
169  }
170 
172  {
173  if (this == nullptr) throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_base_elements().");
174 
175  if (this->seq < 0)
176  return -1;
177  else
178  return nbase;
179  }
180 
182  {
183  int toReturn = 0;
184  if (this == nullptr)
185  throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_base_elements().");
186 
187  if (this->seq < 0)
188  return -1;
189  else
190  {
191  Element* e;
192  for_all_base_elements(e, this)
193  toReturn++;
194  }
195  return toReturn;
196  }
197 
199  {
200  if (this == nullptr)
201  throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_active_elements().");
202  if (this->seq < 0)
203  return -1;
204  else
205  return nactive;
206  }
207 
209  {
210  if (this == nullptr)
211  throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_max_element_id().");
212  if (this->seq < 0)
213  return -1;
214  else
215  return elements.get_size();
216  }
217 
219  {
220  if (this == nullptr)
221  throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_vertex_nodes().");
222  if (this->seq < 0)
223  return -1;
224  else
225  {
226  int to_return = 0;
227  for (int i = 0; i < this->get_num_nodes(); i++)
228  {
229  if (get_node(i)->used && !get_node(i)->type)
230  to_return++;
231  }
232  return to_return;
233  }
234  }
235 
237  {
238  if (this == nullptr)
239  throw Hermes::Exceptions::Exception("this == nullptr in Mesh::get_num_vertex_nodes().");
240  if (this->seq < 0)
241  return -1;
242  else
243  {
244  int to_return = 0;
245  for (int i = 0; i < this->get_num_nodes(); i++)
246  {
247  if (get_node(i)->used && get_node(i)->type)
248  to_return++;
249  }
250  return to_return;
251  }
252  }
253 
254  Element* Mesh::get_element(int id) const
255  {
256  if (id < 0 || id >= elements.get_size())
257  throw Hermes::Exceptions::Exception("Invalid element ID %d, current range:[0; %d]", id, elements.get_size());
258  return &(elements[id]);
259  }
260 
261  unsigned Mesh::get_seq() const
262  {
263  return seq;
264  }
265 
266  void Mesh::calc_bounding_box()
267  {
268  // find bounding box of the whole mesh
269  bool first = true;
270  Node* n;
271  for_all_vertex_nodes(n, this)
272  {
273  if (first)
274  {
275  this->bottom_left_x = this->top_right_x = n->x;
276  this->bottom_left_y = this->top_right_y = n->y;
277  first = false;
278  }
279  else
280  {
281  if (n->x > this->top_right_x)
282  this->top_right_x = n->x;
283  if (n->x < this->bottom_left_x)
284  this->bottom_left_x = n->x;
285  if (n->y > this->top_right_y)
286  this->top_right_y = n->y;
287  if (n->y < this->bottom_left_y)
288  this->bottom_left_y = n->y;
289  }
290  }
291  }
292 
293  void Mesh::get_bounding_box(double& bottom_left_x_, double& bottom_left_y_, double& top_right_x_, double& top_right_y_)
294  {
295  if (!this->bounding_box_calculated)
296  this->calc_bounding_box();
297 
298  top_right_x_ = this->top_right_x;
299  bottom_left_x_ = this->bottom_left_x;
300  top_right_y_ = this->top_right_y;
301  bottom_left_y_ = this->bottom_left_y;
302 
303  bounding_box_calculated = true;
304  }
305 
306  void Mesh::set_seq(unsigned seq)
307  {
308  this->seq = seq;
309  }
310 
312  {
313  return &(elements[id]);
314  }
315 
316  Element* Mesh::create_triangle(int marker, Node* v0, Node* v1, Node* v2, CurvMap* cm, int id)
317  {
318  // create a new_ element
319  Element* e = elements.add();
320 
321  if (id != -1)
322  e->id = id;
323 
324  // initialize the new_ element
325  e->active = 1;
326  e->marker = marker;
327  e->nvert = 3;
328  e->iro_cache = 0;
329  e->cm = cm;
330  e->parent = nullptr;
331  e->visited = false;
332 
333  // set vertex and edge node pointers
334  if (v0 == v1 || v1 == v2 || v2 == v0)
335  throw Hermes::Exceptions::MeshLoadFailureException("Some of the vertices of element #%d are identical which is impossible.", e->id);
336 
337  if (v0->x == v1->x && v0->x == v2->x)
338  throw Hermes::Exceptions::MeshLoadFailureException("Vertices [%i, %i, %i] in element %i share x-coordinates: [%f, %f, %f].", e->id, v0->id, v1->id, v2->id, v0->x, v1->x, v2->x);
339 
340  if (v0->y == v1->y && v0->y == v2->y)
341  throw Hermes::Exceptions::MeshLoadFailureException("Vertices [%i, %i, %i] in element %i share y-coordinates: [%f, %f, %f].", e->id, v0->id, v1->id, v2->id, v0->y, v1->y, v2->y);
342 
343  e->vn[0] = v0;
344  e->vn[1] = v1;
345  e->vn[2] = v2;
346 
347  e->en[0] = get_edge_node(v0->id, v1->id);
348  e->en[1] = get_edge_node(v1->id, v2->id);
349  e->en[2] = get_edge_node(v2->id, v0->id);
350 
351  // register in the nodes
352  e->ref_all_nodes();
353 
354  return e;
355  }
356 
357  Element* Mesh::create_quad(int marker, Node* v0, Node* v1, Node* v2, Node* v3,
358  CurvMap* cm, int id)
359  {
360  // create a new_ element
361  Element* e = elements.add();
362 
363  if (id != -1)
364  e->id = id;
365 
366  // initialize the new_ element
367  e->active = 1;
368  e->marker = marker;
369  e->nvert = 4;
370  e->iro_cache = 0;
371  e->cm = cm;
372  e->parent = nullptr;
373  e->visited = false;
374 
375  // set vertex and edge node pointers
376  if (v0 == v1 || v1 == v2 || v2 == v3 || v3 == v0 || v2 == v0 || v3 == v1)
377  throw Hermes::Exceptions::MeshLoadFailureException("Some of the vertices of element #%d are identical which is not right.", e->id);
378 
379  if ((v0->x == v1->x && v0->x == v2->x) || (v0->x == v1->x && v0->x == v3->x) || (v0->x == v2->x && v0->x == v3->x) || (v1->x == v2->x && v2->x == v3->x))
380  throw Hermes::Exceptions::MeshLoadFailureException("Some of the vertices [%i, %i, %i, %i] in element %i share x-coordinates: [%f, %f, %f, %f].", e->id, v0->id, v1->id, v2->id, v0->x, v1->x, v2->x, v3->x);
381 
382  if ((v0->y == v1->y && v0->y == v2->y) || (v0->y == v1->y && v0->y == v3->y) || (v0->y == v2->y && v0->y == v3->y) || (v1->y == v2->y && v2->y == v3->y))
383  throw Hermes::Exceptions::MeshLoadFailureException("Some of the vertices [%i, %i, %i, %i] in element %i share y-coordinates: [%f, %f, %f, %f].", e->id, v0->id, v1->id, v2->id, v0->y, v1->y, v2->y, v3->y);
384 
385  e->vn[0] = v0;
386  e->vn[1] = v1;
387  e->vn[2] = v2;
388  e->vn[3] = v3;
389 
390  e->en[0] = get_edge_node(v0->id, v1->id);
391  e->en[1] = get_edge_node(v1->id, v2->id);
392  e->en[2] = get_edge_node(v2->id, v3->id);
393  e->en[3] = get_edge_node(v3->id, v0->id);
394 
395  // register in the nodes
396  e->ref_all_nodes();
397 
398  return e;
399  }
400 
401  void Mesh::refine_triangle_to_triangles(Element* e, Element** sons_out)
402  {
403  // remember the markers of the edge nodes
404  int bnd[3] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd };
405  int mrk[3] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker };
406 
407  // obtain three mid-edge vertex nodes
408  Node* x0, *x1, *x2;
409  x0 = get_vertex_node(e->vn[0]->id, e->vn[1]->id);
410  x1 = get_vertex_node(e->vn[1]->id, e->vn[2]->id);
411  x2 = get_vertex_node(e->vn[2]->id, e->vn[0]->id);
412 
413  CurvMap* cm[H2D_MAX_NUMBER_EDGES];
414  memset(cm, 0, H2D_MAX_NUMBER_EDGES * sizeof(CurvMap*));
415 
416  // adjust mid-edge coordinates if this is a curved element
417  if (e->is_curved())
418  {
419  double2 pt[3] = { { 0.0, -1.0 }, { 0.0, 0.0 }, { -1.0, 0.0 } };
420  e->cm->get_mid_edge_points(e, pt, 3);
421  x0->x = pt[0][0]; x0->y = pt[0][1];
422  x1->x = pt[1][0]; x1->y = pt[1][1];
423  x2->x = pt[2][0]; x2->y = pt[2][1];
424 
425  // create CurvMaps for sons (pointer to parent element, part)
426  for (int i = 0; i < 4; i++)
427  cm[i] = CurvMap::create_son_curv_map(e, i);
428  }
429 
430  // create the four sons
431  Element* sons[H2D_MAX_ELEMENT_SONS];
432  sons[0] = create_triangle(e->marker, e->vn[0], x0, x2, cm[0]);
433  sons[1] = create_triangle(e->marker, x0, e->vn[1], x1, cm[1]);
434  sons[2] = create_triangle(e->marker, x2, x1, e->vn[2], cm[2]);
435  sons[3] = create_triangle(e->marker, x1, x2, x0, cm[3]);
436 
437  // update coefficients of curved reference mapping
438  for (int i = 0; i < 4; i++)
439  if (sons[i]->is_curved())
440  sons[i]->cm->update_refmap_coeffs(sons[i]);
441 
442  // deactivate this element and unregister from its nodes
443  e->active = 0;
444  this->nactive += 3;
445  e->unref_all_nodes(this);
446 
447  // now the original edge nodes may no longer exist...
448  // set correct boundary status and markers for the new_ nodes
449  sons[0]->en[0]->bnd = bnd[0]; sons[0]->en[0]->marker = mrk[0];
450  sons[0]->en[2]->bnd = bnd[2]; sons[0]->en[2]->marker = mrk[2];
451  sons[1]->en[0]->bnd = bnd[0]; sons[1]->en[0]->marker = mrk[0];
452  sons[1]->en[1]->bnd = bnd[1]; sons[1]->en[1]->marker = mrk[1];
453  sons[2]->en[1]->bnd = bnd[1]; sons[2]->en[1]->marker = mrk[1];
454  sons[2]->en[2]->bnd = bnd[2]; sons[2]->en[2]->marker = mrk[2];
455  sons[3]->vn[0]->bnd = bnd[1];
456  sons[3]->vn[1]->bnd = bnd[2];
457  sons[3]->vn[2]->bnd = bnd[0];
458 
459  //set pointers to parent element for sons
460  for (int i = 0; i < 4; i++)
461  {
462  if (sons[i] != nullptr) sons[i]->parent = e;
463  }
464 
465  // copy son pointers (could not have been done earlier because of the union)
466  memcpy(e->sons, sons, 4 * sizeof(Element*));
467 
468  // If sons_out != nullptr, copy son pointers there.
469  if (sons_out != nullptr)
470  {
471  for (int i = 0; i < 3; i++) sons_out[i] = sons[i];
472  }
473  }
474 
475  Node* get_vertex_node(Node* v1, Node* v2)
476  {
477  // initialize the new_ Node
478  Node* newnode = new Node();
479  newnode->type = HERMES_TYPE_VERTEX;
480  newnode->ref = 0;
481  newnode->bnd = 0;
482  newnode->p1 = -9999;
483  newnode->p2 = -9999;
484  newnode->x = (v1->x + v2->x) * 0.5;
485  newnode->y = (v1->y + v2->y) * 0.5;
486 
487  return newnode;
488  }
489 
490  Node* get_edge_node()
491  {
492  // initialize the new_ Node
493  Node* newnode = new Node();
494  newnode->type = HERMES_TYPE_EDGE;
495  newnode->ref = 0;
496  newnode->bnd = 0;
497  newnode->p1 = -9999;
498  newnode->p2 = -9999;
499  newnode->marker = 0;
500  newnode->elem[0] = newnode->elem[1] = nullptr;
501 
502  return newnode;
503  }
504 
505  void Mesh::refine_quad(Element* e, int refinement, Element** sons_out)
506  {
507  int i, j;
508  Element* sons[H2D_MAX_ELEMENT_SONS] = { nullptr, nullptr, nullptr, nullptr };
509 
510  // remember the markers of the edge nodes
511  int bnd[H2D_MAX_NUMBER_EDGES] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd, e->en[3]->bnd };
512  int mrk[H2D_MAX_NUMBER_EDGES] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker, e->en[3]->marker };
513 
514  // deactivate this element and unregister from its nodes
515  e->active = false;
516  nactive--;
517  e->unref_all_nodes(this);
518 
519  // now the original edge nodes may no longer exist...
521  memset(cm, 0, sizeof(cm));
522 
523  // default refinement: one quad to four quads
524  if (refinement == 0)
525  {
526  // obtain four mid-edge vertex nodes and one mid-element vertex node
527  Node* x0, *x1, *x2, *x3, *mid;
528  x0 = get_vertex_node(e->vn[0]->id, e->vn[1]->id);
529  x1 = get_vertex_node(e->vn[1]->id, e->vn[2]->id);
530  x2 = get_vertex_node(e->vn[2]->id, e->vn[3]->id);
531  x3 = get_vertex_node(e->vn[3]->id, e->vn[0]->id);
532  mid = get_vertex_node(x0->id, x2->id);
533 
534  // adjust mid-edge coordinates if this is a curved element
535  if (e->is_curved())
536  {
537  double2 pt[5] = { { 0.0, -1.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { -1.0, 0.0 }, { 0.0, 0.0 } };
538  e->cm->get_mid_edge_points(e, pt, 5);
539  x0->x = pt[0][0]; x0->y = pt[0][1];
540  x1->x = pt[1][0]; x1->y = pt[1][1];
541  x2->x = pt[2][0]; x2->y = pt[2][1];
542  x3->x = pt[3][0]; x3->y = pt[3][1];
543  mid->x = pt[4][0]; mid->y = pt[4][1];
544 
545  // create CurvMaps for sons (pointer to parent element, part)
546  for (i = 0; i < H2D_MAX_ELEMENT_SONS; i++)
547  cm[i] = CurvMap::create_son_curv_map(e, i);
548  }
549 
550  // create the four sons
551  sons[0] = create_quad(e->marker, e->vn[0], x0, mid, x3, cm[0]);
552  sons[1] = create_quad(e->marker, x0, e->vn[1], x1, mid, cm[1]);
553  sons[2] = create_quad(e->marker, mid, x1, e->vn[2], x2, cm[2]);
554  sons[3] = create_quad(e->marker, x3, mid, x2, e->vn[3], cm[3]);
555 
556  // Increase the number of active elements by 4.
557  this->nactive += H2D_MAX_ELEMENT_SONS;
558 
559  // set correct boundary markers for the new_ edge nodes
560  for (i = 0; i < H2D_MAX_NUMBER_EDGES; i++)
561  {
562  j = (i > 0) ? i - 1 : 3;
563  sons[i]->en[j]->bnd = bnd[j]; sons[i]->en[j]->marker = mrk[j];
564  sons[i]->en[i]->bnd = bnd[i]; sons[i]->en[i]->marker = mrk[i];
565  sons[i]->vn[j]->bnd = bnd[j];
566  }
567  }
568 
569  // refinement '1': one quad to two 'horizontal' quads
570  else if (refinement == 1)
571  {
572  Node* x1, *x3;
573  x1 = get_vertex_node(e->vn[1]->id, e->vn[2]->id);
574  x3 = get_vertex_node(e->vn[3]->id, e->vn[0]->id);
575 
576  // adjust mid-edge coordinates if this is a curved element
577  if (e->is_curved())
578  {
579  double2 pt[2] = { { 1.0, 0.0 }, { -1.0, 0.0 } };
580  e->cm->get_mid_edge_points(e, pt, 2);
581  x1->x = pt[0][0]; x1->y = pt[0][1];
582  x3->x = pt[1][0]; x3->y = pt[1][1];
583 
584  // create CurvMaps for sons (pointer to parent element, part)
585  for (i = 0; i < 2; i++)
586  cm[i] = CurvMap::create_son_curv_map(e, i + 4);
587  }
588 
589  sons[0] = create_quad(e->marker, e->vn[0], e->vn[1], x1, x3, cm[0]);
590  sons[1] = create_quad(e->marker, x3, x1, e->vn[2], e->vn[3], cm[1]);
591  sons[2] = sons[3] = nullptr;
592 
593  this->nactive += 2;
594 
595  sons[0]->en[0]->bnd = bnd[0]; sons[0]->en[0]->marker = mrk[0];
596  sons[0]->en[1]->bnd = bnd[1]; sons[0]->en[1]->marker = mrk[1];
597  sons[0]->en[3]->bnd = bnd[3]; sons[0]->en[3]->marker = mrk[3];
598  sons[1]->en[1]->bnd = bnd[1]; sons[1]->en[1]->marker = mrk[1];
599  sons[1]->en[2]->bnd = bnd[2]; sons[1]->en[2]->marker = mrk[2];
600  sons[1]->en[3]->bnd = bnd[3]; sons[1]->en[3]->marker = mrk[3];
601  sons[0]->vn[2]->bnd = bnd[1];
602  sons[0]->vn[3]->bnd = bnd[3];
603  }
604 
605  // refinement '2': one quad to two 'vertical' quads
606  else if (refinement == 2)
607  {
608  Node* x0, *x2;
609  x0 = get_vertex_node(e->vn[0]->id, e->vn[1]->id);
610  x2 = get_vertex_node(e->vn[2]->id, e->vn[3]->id);
611 
612  // adjust mid-edge coordinates if this is a curved element
613  if (e->is_curved())
614  {
615  double2 pt[2] = { { 0.0, -1.0 }, { 0.0, 1.0 } };
616  e->cm->get_mid_edge_points(e, pt, 2);
617  x0->x = pt[0][0]; x0->y = pt[0][1];
618  x2->x = pt[1][0]; x2->y = pt[1][1];
619 
620  // create CurvMaps for sons (pointer to parent element, part)
621  for (i = 0; i < 2; i++)
622  cm[i] = CurvMap::create_son_curv_map(e, i + 6);
623  }
624 
625  sons[0] = sons[1] = nullptr;
626  sons[2] = create_quad(e->marker, e->vn[0], x0, x2, e->vn[3], cm[0]);
627  sons[3] = create_quad(e->marker, x0, e->vn[1], e->vn[2], x2, cm[1]);
628 
629  this->nactive += 2;
630 
631  sons[2]->en[0]->bnd = bnd[0]; sons[2]->en[0]->marker = mrk[0];
632  sons[2]->en[2]->bnd = bnd[2]; sons[2]->en[2]->marker = mrk[2];
633  sons[2]->en[3]->bnd = bnd[3]; sons[2]->en[3]->marker = mrk[3];
634  sons[3]->en[0]->bnd = bnd[0]; sons[3]->en[0]->marker = mrk[0];
635  sons[3]->en[1]->bnd = bnd[1]; sons[3]->en[1]->marker = mrk[1];
636  sons[3]->en[2]->bnd = bnd[2]; sons[3]->en[2]->marker = mrk[2];
637  sons[2]->vn[1]->bnd = bnd[0];
638  sons[2]->vn[2]->bnd = bnd[2];
639  }
640  else assert(0);
641 
642  // update coefficients of curved reference mapping
643  for (i = 0; i < 4; i++)
644  if (sons[i])
645  {
646  if (sons[i]->cm)
647  sons[i]->cm->update_refmap_coeffs(sons[i]);
648  }
649 
650  // set pointers to parent element for sons
651  for (int i = 0; i < 4; i++)
652  if (sons[i] != nullptr)
653  sons[i]->parent = e;
654 
655  // copy son pointers (could not have been done earlier because of the union)
656  memcpy(e->sons, sons, sizeof(sons));
657 
658  // If sons_out != nullptr, copy son pointers there.
659  if (sons_out != nullptr)
660  {
661  for (int i = 0; i < 4; i++)
662  sons_out[i] = sons[i];
663  }
664  }
665 
666  void Mesh::unrefine_element_internal(Element* e)
667  {
668  this->refinements.push_back(std::pair<unsigned int, int>(e->id, -1));
669  assert(!e->active);
670  unsigned int i;
671  int s1, s2;
672 
673  // obtain markers and bnds from son elements
675  for (unsigned i = 0; i < e->get_nvert(); i++)
676  {
677  MeshUtil::get_edge_sons(e, i, s1, s2);
678  assert(e->sons[s1]->active);
679  mrk[i] = e->sons[s1]->en[i]->marker;
680  bnd[i] = e->sons[s1]->en[i]->bnd;
681  }
682 
683  // remove all sons
684  for (i = 0; i < H2D_MAX_ELEMENT_SONS; i++)
685  {
686  Element* son = e->sons[i];
687  if (son != nullptr)
688  {
689  son->unref_all_nodes(this);
690  if (son->cm != nullptr)
691  {
692  delete son->cm;
693  son->cm = nullptr;
694  }
695  elements.remove(son->id);
696  this->nactive--;
697  }
698  }
699 
700  // recreate edge nodes
701  for (i = 0; i < e->get_nvert(); i++)
702  e->en[i] = this->get_edge_node(e->vn[i]->id, e->vn[e->next_vert(i)]->id);
703 
704  e->ref_all_nodes();
705  e->active = 1;
706  nactive++;
707 
708  // restore edge node markers and bnds
709  for (i = 0; i < e->get_nvert(); i++)
710  {
711  e->en[i]->marker = mrk[i];
712  e->en[i]->bnd = bnd[i];
713  }
714  }
715 
716  void Mesh::refine_element(Element* e, int refinement)
717  {
718  this->refinements.push_back(std::pair<unsigned int, int>(e->id, refinement));
719 
720  if (e->is_triangle())
721  {
722  if (refinement == 3)
723  {
724  refine_triangle_to_quads(e);
725  }
726  else
727  {
728  this->refine_triangle_to_triangles(e);
729  }
730  }
731  else refine_quad(e, refinement);
732 
733  for (int i = 0; i < H2D_MAX_ELEMENT_SONS; i++)
734  if (e->sons[i])
735  e->sons[i]->iro_cache = e->iro_cache;
736 
737  this->seq = g_mesh_seq++;
738  }
739 
740  void Mesh::refine_element_id(int id, int refinement)
741  {
742  if (refinement == -1)
743  return;
744  Element* e = this->get_element(id);
745  if (!e->used)
746  throw Hermes::Exceptions::Exception("Invalid element id number.");
747  if (!e->active)
748  throw Hermes::Exceptions::Exception("Attempt to refine element #%d which has been refined already.", e->id);
749  this->refine_element(e, refinement);
750  }
751 
752  void Mesh::refine_all_elements(int refinement, bool mark_as_initial)
753  {
754  ninitial = this->get_max_element_id();
755 
756  if (refinement == -1)
757  return;
758 
759  elements.set_append_only(true);
760 
761  Element* e;
762 
763  for_all_active_elements(e, this)
764  refine_element(e, refinement);
765 
766  elements.set_append_only(false);
767 
768  if (mark_as_initial)
769  ninitial = this->get_max_element_id();
770  }
771 
772  static int rtb_marker;
773  static bool rtb_aniso;
774  static char* rtb_vert;
775 
776  void Mesh::refine_by_criterion(int(*criterion)(Element*), int depth, bool mark_as_initial)
777  {
778  Element* e;
779  elements.set_append_only(true);
780  for (int r, i = 0; i < depth; i++)
781  {
782  for_all_active_elements(e, this)
783  {
784  if ((r = criterion(e)) >= 0)
785  refine_element_id(e->id, r);
786  }
787  }
788  elements.set_append_only(false);
789 
790  if (mark_as_initial)
791  ninitial = this->get_max_element_id();
792  }
793 
794  static int rtv_id;
795 
796  static int rtv_criterion(Element* e)
797  {
798  for (unsigned int i = 0; i < e->get_nvert(); i++)
799  if (e->vn[i]->id == rtv_id)
800  return 0;
801  return -1;
802  }
803 
804  void Mesh::refine_towards_vertex(int vertex_id, int depth, bool mark_as_initial)
805  {
806  rtv_id = vertex_id;
807  refine_by_criterion(rtv_criterion, depth);
808  if (mark_as_initial)
809  ninitial = this->get_max_element_id();
810  }
811 
812  int rtb_criterion(Element* e)
813  {
814  unsigned int i;
815  for (i = 0; i < e->get_nvert(); i++)
816  {
817  if (e->en[i]->marker == rtb_marker || rtb_vert[e->vn[i]->id])
818  {
819  break;
820  }
821  }
822 
823  if (i >= e->get_nvert()) return -1;
824  // triangle should be split into 3 quads
825  // if(e->is_triangle() && rtb_tria_to_quad) return 3;
826  // triangle should be split into 4 triangles or quad should
827  // be split into 4 quads
828  if (e->is_triangle() || !rtb_aniso) return 0;
829 
830  // quads - anisotropic case 1
831  if ((e->en[0]->marker == rtb_marker && !rtb_vert[e->vn[2]->id] && !rtb_vert[e->vn[3]->id]) ||
832  (e->en[2]->marker == rtb_marker && !rtb_vert[e->vn[0]->id] && !rtb_vert[e->vn[1]->id]) ||
833  (e->en[0]->marker == rtb_marker && e->en[2]->marker == rtb_marker &&
834  e->en[1]->marker != rtb_marker && e->en[3]->marker != rtb_marker)) return 1;
835 
836  // quads - anisotropic case 2
837  if ((e->en[1]->marker == rtb_marker && !rtb_vert[e->vn[3]->id] && !rtb_vert[e->vn[0]->id]) ||
838  (e->en[3]->marker == rtb_marker && !rtb_vert[e->vn[1]->id] && !rtb_vert[e->vn[2]->id]) ||
839  (e->en[1]->marker == rtb_marker && e->en[3]->marker == rtb_marker &&
840  e->en[0]->marker != rtb_marker && e->en[2]->marker != rtb_marker)) return 2;
841 
842  return 0;
843  }
844 
845  void Mesh::refine_towards_boundary(std::vector<std::string> markers, int depth, bool aniso, bool mark_as_initial)
846  {
847  rtb_aniso = aniso;
848  bool refined = true;
849 
850  // refinement: refine all elements to quad elements.
851  for (int i = 0; i < depth; i++)
852  {
853  refined = false;
854  int size = get_max_node_id() + 1;
855  rtb_vert = new char[size];
856  memset(rtb_vert, 0, sizeof(char)* size);
857 
858  Element* e;
859  for_all_active_elements(e, this)
860  for (unsigned int j = 0; j < e->get_nvert(); j++)
861  {
862  bool marker_matched = false;
863  for (unsigned int marker_i = 0; marker_i < markers.size(); marker_i++)
864  if (e->en[j]->marker == this->boundary_markers_conversion.get_internal_marker(markers[marker_i]).marker)
865  marker_matched = true;
866  if (marker_matched)
867  {
868  rtb_vert[e->vn[j]->id] = rtb_vert[e->vn[e->next_vert(j)]->id] = 1;
869  refined = true;
870  }
871  }
872 
873  refine_by_criterion(rtb_criterion, 1);
874  delete[] rtb_vert;
875  }
876 
877  if (mark_as_initial)
878  ninitial = this->get_max_element_id();
879  if (!refined)
880  throw Hermes::Exceptions::Exception("None of the markers in Mesh::refine_towards_boundary found in the Mesh.");
881  }
882 
883  void Mesh::refine_towards_boundary(std::string marker, int depth, bool aniso, bool mark_as_initial)
884  {
885  if (marker == HERMES_ANY)
886  for (std::map<int, std::string>::iterator it = this->boundary_markers_conversion.conversion_table.begin(); it != this->boundary_markers_conversion.conversion_table.end(); ++it)
887  refine_towards_boundary(it->second, depth, aniso, mark_as_initial);
888 
889  else
890  {
891  bool refined = true;
892  rtb_marker = this->boundary_markers_conversion.get_internal_marker(marker).marker;
893  rtb_aniso = aniso;
894 
895  // refinement: refine all elements to quad elements.
896  for (int i = 0; i < depth; i++)
897  {
898  refined = false;
899  int size = get_max_node_id() + 1;
900  rtb_vert = new char[size];
901  memset(rtb_vert, 0, sizeof(char)* size);
902 
903  Element* e;
904  for_all_active_elements(e, this)
905  for (unsigned int j = 0; j < e->get_nvert(); j++)
906  {
907  if (e->en[j]->marker == rtb_marker)
908  {
909  rtb_vert[e->vn[j]->id] = rtb_vert[e->vn[e->next_vert(j)]->id] = 1;
910  refined = true;
911  }
912  }
913 
914  refine_by_criterion(rtb_criterion, 1);
915  delete[] rtb_vert;
916  }
917 
918  if (mark_as_initial)
919  ninitial = this->get_max_element_id();
920  if (!refined)
921  throw Hermes::Exceptions::Exception("None of the markers in Mesh::refine_towards_boundary found in the Mesh.");
922  }
923  }
924 
925  void Mesh::refine_in_area(std::string marker, int depth, int refinement, bool mark_as_initial)
926  {
927  std::vector<std::string> markers;
928  markers.push_back(marker);
929  this->refine_in_areas(markers, depth, refinement, mark_as_initial);
930  }
931 
932  void Mesh::refine_in_areas(std::vector<std::string> markers, int depth, int refinement, bool mark_as_initial)
933  {
934  std::vector<int> internal_markers;
935  bool any_marker = false;
936  for (unsigned int marker_i = 0; marker_i < markers.size(); marker_i++)
937  {
938  if (markers[marker_i] == HERMES_ANY)
939  {
940  any_marker = true;
941  break;
942  }
943  int marker = this->element_markers_conversion.get_internal_marker(markers[marker_i]).marker;
944 
945  internal_markers.push_back(marker);
946  }
947 
948  bool refined = true;
949  for (int i = 0; i < depth; i++)
950  {
951  refined = false;
952  Element* e;
953  if (any_marker)
954  {
955  for_all_active_elements(e, this)
956  {
957  this->refine_element(e, refinement);
958  refined = true;
959  }
960  }
961  else
962  {
963  for_all_active_elements(e, this)
964  {
965  for (unsigned int marker_i = 0; marker_i < internal_markers.size(); marker_i++)
966  if (e->marker == internal_markers[marker_i])
967  {
968  this->refine_element(e, refinement);
969  refined = true;
970  }
971  }
972  }
973  }
974 
975  if (mark_as_initial)
976  ninitial = this->get_max_element_id();
977  if (!refined)
978  throw Hermes::Exceptions::Exception("None of the markers in Mesh::refine_in_areas found in the Mesh.");
979  }
980 
982  {
983  Element* e = get_element(id);
984  if (!e->used) throw Hermes::Exceptions::Exception("Invalid element id number.");
985  if (e->active) return;
986 
987  for (int i = 0; i < 4; i++)
988  if (e->sons[i] != nullptr)
989  unrefine_element_id(e->sons[i]->id);
990 
991  unrefine_element_internal(e);
992  seq = g_mesh_seq++;
993  }
994 
995  void Mesh::unrefine_all_elements(bool keep_initial_refinements)
996  {
997  // find inactive elements with active sons
998  std::vector<int> list;
999  Element* e;
1000  for_all_inactive_elements(e, this)
1001  {
1002  bool found = true;
1003  for (unsigned int i = 0; i < 4; i++)
1004  if (e->sons[i] != nullptr &&
1005  (!e->sons[i]->active || (keep_initial_refinements && e->sons[i]->id < ninitial))
1006  )
1007  {
1008  found = false; break;
1009  }
1010 
1011  if (found) list.push_back(e->id);
1012  }
1013 
1014  // unrefine the found elements
1015  for (unsigned int i = 0; i < list.size(); i++)
1016  unrefine_element_id(list[i]);
1017  }
1018 
1019  double Mesh::vector_length(double a_1, double a_2)
1020  {
1021  return sqrt(sqr(a_1) + sqr(a_2));
1022  }
1023 
1024  bool Mesh::same_line(double p_1, double p_2, double q_1, double q_2, double r_1, double r_2)
1025  {
1026  double pq_1 = q_1 - p_1, pq_2 = q_2 - p_2, pr_1 = r_1 - p_1, pr_2 = r_2 - p_2;
1027  double length_pq = vector_length(pq_1, pq_2);
1028  double length_pr = vector_length(pr_1, pr_2);
1029  double sin_angle = (pq_1*pr_2 - pq_2*pr_1) / (length_pq*length_pr);
1030  if (fabs(sin_angle) < Hermes::HermesEpsilon) return true;
1031  else return false;
1032  }
1033 
1034  bool Mesh::is_convex(double a_1, double a_2, double b_1, double b_2)
1035  {
1036  if (a_1*b_2 - a_2*b_1 > 0) return true;
1037  else return false;
1038  }
1039 
1040  void Mesh::check_triangle(int i, Node *&v0, Node *&v1, Node *&v2)
1041  {
1042  // checking that all edges have nonzero length
1043  double
1044  length_1 = vector_length(v1->x - v0->x, v1->y - v0->y),
1045  length_2 = vector_length(v2->x - v1->x, v2->y - v1->y),
1046  length_3 = vector_length(v0->x - v2->x, v0->y - v2->y);
1047  if (length_1 < Hermes::HermesSqrtEpsilon || length_2 < Hermes::HermesSqrtEpsilon || length_3 < Hermes::HermesSqrtEpsilon)
1048  throw Hermes::Exceptions::Exception("Edge of triangular element #%d has length less than Hermes::HermesSqrtEpsilon.", i);
1049 
1050  // checking that vertices do not lie on the same line
1051  if (same_line(v0->x, v0->y, v1->x, v1->y, v2->x, v2->y))
1052  throw Hermes::Exceptions::Exception("Triangular element #%d: all vertices lie on the same line.", i);
1053 
1054  // checking positive orientation. If not positive, swapping vertices
1055  if (!is_convex(v1->x - v0->x, v1->y - v0->y, v2->x - v0->x, v2->y - v0->y))
1056  {
1057  std::swap(v1, v2);
1058  }
1059  }
1060 
1061  void Mesh::check_quad(int i, Node *&v0, Node *&v1, Node *&v2, Node *&v3)
1062  {
1063  // checking that all edges have nonzero length
1064  double
1065  length_1 = vector_length(v1->x - v0->x, v1->y - v0->y),
1066  length_2 = vector_length(v2->x - v1->x, v2->y - v1->y),
1067  length_3 = vector_length(v3->x - v2->x, v3->y - v2->y),
1068  length_4 = vector_length(v0->x - v3->x, v0->y - v3->y);
1069  if (length_1 < Hermes::HermesSqrtEpsilon || length_2 < Hermes::HermesSqrtEpsilon || length_3 < Hermes::HermesSqrtEpsilon || length_4 < Hermes::HermesSqrtEpsilon)
1070  throw Hermes::Exceptions::Exception("Edge of quad element #%d has length less than Hermes::HermesSqrtEpsilon.", i);
1071 
1072  // checking that both diagonals have nonzero length
1073  double
1074  diag_1 = vector_length(v2->x - v0->x, v2->y - v0->y),
1075  diag_2 = vector_length(v3->x - v1->x, v3->y - v1->y);
1076  if (diag_1 < Hermes::HermesSqrtEpsilon || diag_2 < Hermes::HermesSqrtEpsilon)
1077  throw Hermes::Exceptions::Exception("Diagonal of quad element #%d has length less than Hermes::HermesSqrtEpsilon.", i);
1078 
1079  // checking that vertices v0, v1, v2 do not lie on the same line
1080  if (same_line(v0->x, v0->y, v1->x, v1->y, v2->x, v2->y))
1081  throw Hermes::Exceptions::Exception("Quad element #%d: vertices v0, v1, v2 lie on the same line.", i);
1082  // checking that vertices v0, v1, v3 do not lie on the same line
1083  if (same_line(v0->x, v0->y, v1->x, v1->y, v3->x, v3->y))
1084  throw Hermes::Exceptions::Exception("Quad element #%d: vertices v0, v1, v3 lie on the same line.", i);
1085  // checking that vertices v0, v2, v3 do not lie on the same line
1086  if (same_line(v0->x, v0->y, v2->x, v2->y, v3->x, v3->y))
1087  throw Hermes::Exceptions::Exception("Quad element #%d: vertices v0, v2, v3 lie on the same line.", i);
1088  // checking that vertices v1, v2, v3 do not lie on the same line
1089  if (same_line(v1->x, v1->y, v2->x, v2->y, v3->x, v3->y))
1090  throw Hermes::Exceptions::Exception("Quad element #%d: vertices v1, v2, v3 lie on the same line.", i);
1091 
1092  // checking that vertex v1 lies on the right of the diagonal v2-v0
1093  int vertex_1_ok = is_convex(v1->x - v0->x, v1->y - v0->y, v2->x - v0->x, v2->y - v0->y);
1094  if (!vertex_1_ok) throw Hermes::Exceptions::Exception("Vertex v1 of quad element #%d does not lie on the right of the diagonal v2-v0.", i);
1095  // checking that vertex v3 lies on the left of the diagonal v2-v0
1096  int vertex_3_ok = is_convex(v2->x - v0->x, v2->y - v0->y, v3->x - v0->x, v3->y - v0->y);
1097  if (!vertex_3_ok) throw Hermes::Exceptions::Exception("Vertex v3 of quad element #%d does not lie on the left of the diagonal v2-v0.", i);
1098  // checking that vertex v2 lies on the right of the diagonal v3-v1
1099  int vertex_2_ok = is_convex(v2->x - v1->x, v2->y - v1->y, v3->x - v1->x, v3->y - v1->y);
1100  if (!vertex_2_ok) throw Hermes::Exceptions::Exception("Vertex v2 of quad element #%d does not lie on the right of the diagonal v3-v1.", i);
1101  // checking that vertex v0 lies on the left of the diagonal v3-v1
1102  int vertex_0_ok = is_convex(v3->x - v1->x, v3->y - v1->y, v0->x - v1->x, v0->y - v1->y);
1103  if (!vertex_0_ok) throw Hermes::Exceptions::Exception("Vertex v0 of quad element #%d does not lie on the left of the diagonal v2-v1.", i);
1104  }
1105 
1106  bool Mesh::rescale(double x_ref, double y_ref)
1107  {
1108  // Go through all vertices and rescale coordinates.
1109  Node* n;
1110  for_all_vertex_nodes(n, this) {
1111  n->x /= x_ref;
1112  n->y /= y_ref;
1113  }
1114 
1115  // If curvilinear, throw an exception.
1116  Element* e;
1117  for_all_used_elements(e, this)
1118  if (e->cm != nullptr)
1119  {
1120  throw CurvedException(e->id);
1121  return false;
1122  }
1123  return true;
1124  }
1125 
1126  void Mesh::copy(MeshSharedPtr mesh)
1127  {
1128  unsigned int i;
1129 
1130  free();
1131 
1132  // copy nodes and elements
1133  HashTable::copy(mesh.get());
1134  elements.copy(mesh->elements);
1135 
1136  this->refinements = mesh->refinements;
1137 
1138  Element* e;
1139  for_all_used_elements(e, this)
1140  {
1141  // update vertex node pointers
1142  for (i = 0; i < e->get_nvert(); i++)
1143  e->vn[i] = &nodes[e->vn[i]->id];
1144 
1145  if (e->active)
1146  {
1147  // update edge node pointers
1148  for (i = 0; i < e->get_nvert(); i++)
1149  e->en[i] = &nodes[e->en[i]->id];
1150  }
1151  else
1152  {
1153  // update son pointers
1154  for (i = 0; i < 4; i++)
1155  if (e->sons[i] != nullptr)
1156  e->sons[i] = &elements[e->sons[i]->id];
1157  }
1158 
1159  // copy CurvMap, update its parent
1160  if (e->cm != nullptr)
1161  {
1162  e->cm = new CurvMap(e->cm);
1163  if (!e->cm->toplevel)
1164  e->cm->parent = &elements[e->cm->parent->id];
1165  }
1166 
1167  //update parent pointer
1168  if (e->parent != nullptr)
1169  e->parent = &elements[e->parent->id];
1170  }
1171 
1172  // update element pointers in edge nodes
1173  Node* node;
1174  for_all_edge_nodes(node, this)
1175  for (i = 0; i < 2; i++)
1176  if (node->elem[i] != nullptr)
1177  node->elem[i] = &elements[node->elem[i]->id];
1178 
1179  nbase = mesh->nbase;
1180  nactive = mesh->nactive;
1181  ntopvert = mesh->ntopvert;
1182  ninitial = mesh->ninitial;
1183  seq = mesh->seq;
1184  boundary_markers_conversion = mesh->boundary_markers_conversion;
1185  element_markers_conversion = mesh->element_markers_conversion;
1186  }
1187 
1188  void Mesh::init(int size)
1189  {
1190  HashTable::init(size);
1191  }
1192 
1193  void Mesh::copy_base(MeshSharedPtr mesh)
1194  {
1195  //printf("Calling Mesh::free() in Mesh::copy_base().\n");
1196  free();
1197  init();
1198 
1199  // copy top-level vertex nodes
1200  for (int i = 0; i < mesh->get_max_node_id(); i++)
1201  {
1202  Node* node = &(mesh->nodes[i]);
1203  if (node->ref < TOP_LEVEL_REF) break;
1204  Node* newnode = nodes.add();
1205  assert(newnode->id == i && node->type == HERMES_TYPE_VERTEX);
1206  memcpy(newnode, node, sizeof(Node));
1207  newnode->ref = TOP_LEVEL_REF;
1208  }
1209 
1210  // copy base elements
1211  Element* e;
1212  for (int id = 0; id < mesh->get_num_base_elements(); id++)
1213  {
1214  e = mesh->get_element_fast(id);
1215  if (!e->used)
1216  {
1217  Element* e_temp = elements.add();
1218  e_temp->used = false;
1219  e_temp->cm = nullptr;
1220  continue;
1221  }
1222  Element* enew;
1223  Node *v0 = &nodes[e->vn[0]->id], *v1 = &nodes[e->vn[1]->id], *v2 = &nodes[e->vn[2]->id];
1224  if (e->is_triangle())
1225  enew = this->create_triangle(e->marker, v0, v1, v2, nullptr);
1226  else
1227  enew = this->create_quad(e->marker, v0, v1, v2, &nodes[e->vn[3]->id], nullptr);
1228 
1229  // copy edge markers
1230  for (unsigned int j = 0; j < e->get_nvert(); j++)
1231  {
1232  Node* en = MeshUtil::get_base_edge_node(e, j);
1233  // copy bnd data from the active el.
1234  enew->en[j]->bnd = en->bnd;
1235  enew->en[j]->marker = en->marker;
1236  }
1237 
1238  if (e->is_curved())
1239  enew->cm = new CurvMap(e->cm);
1240  }
1241 
1242  this->boundary_markers_conversion = mesh->boundary_markers_conversion;
1243  this->element_markers_conversion = mesh->element_markers_conversion;
1244 
1245  nbase = nactive = ninitial = mesh->nbase;
1246  ntopvert = mesh->ntopvert;
1247  seq = g_mesh_seq++;
1248  }
1249 
1250  void Mesh::free()
1251  {
1252  Element* e;
1253  for_all_elements(e, this)
1254  {
1255  if (e->cm != nullptr)
1256  {
1257  delete e->cm;
1258  e->cm = nullptr;
1259  }
1260  }
1261  elements.free();
1262  HashTable::free();
1263 
1264  if (this->meshHashGrid)
1265  delete this->meshHashGrid;
1266 
1267  this->boundary_markers_conversion.conversion_table.clear();
1268  this->boundary_markers_conversion.conversion_table_inverse.clear();
1269  this->element_markers_conversion.conversion_table.clear();
1270  this->element_markers_conversion.conversion_table_inverse.clear();
1271  this->refinements.clear();
1272  this->seq = -1;
1273 
1274  for (std::map<int, MarkerArea*>::iterator p = marker_areas.begin(); p != marker_areas.end(); p++)
1275  delete p->second;
1276  marker_areas.clear();
1277  }
1278 
1280  {
1281  // If no hash grid exists, create one.
1282  if (!this->meshHashGrid)
1283  this->meshHashGrid = new MeshHashGrid(this);
1284  else
1285  {
1286  // If no the hash grid exists, but the mesh has been refined afterwards, re-create.
1287  if (this->get_seq() != this->meshHashGrid->get_mesh_seq())
1288  {
1289  delete this->meshHashGrid;
1290  this->meshHashGrid = new MeshHashGrid(this);
1291  }
1292  }
1293 
1294  return this->meshHashGrid->getElement(x, y);
1295  }
1296 
1297  double Mesh::get_marker_area(int marker)
1298  {
1299  std::map<int, MarkerArea*>::iterator area = marker_areas.find(marker);
1300  bool recalculate = false;
1301  if (area == marker_areas.end())
1302  {
1303  recalculate = true;
1304  }
1305  else
1306  {
1307  if (area->second->get_mesh_seq() != this->get_seq())
1308  {
1309  delete area->second;
1310  marker_areas.erase(area);
1311  recalculate = true;
1312  }
1313  }
1314 
1315  if (recalculate)
1316  marker_areas.insert(std::pair<int, MarkerArea*>(marker, new MarkerArea(this, marker)));
1317 
1318  return marker_areas.find(marker)->second->get_area();
1319  }
1320 
1321  void Mesh::copy_converted(MeshSharedPtr mesh)
1322  {
1323  free();
1324  HashTable::copy(mesh.get());
1325  this->boundary_markers_conversion = mesh->boundary_markers_conversion;
1326  this->element_markers_conversion = mesh->element_markers_conversion;
1327 
1328  // clear reference for all nodes
1329  for (int i = 0; i < nodes.get_size(); i++)
1330  {
1331  Node& node = nodes[i];
1332  if (node.type == HERMES_TYPE_EDGE) { //process only edge nodes
1333  for (int k = 0; k < 2; k++)
1334  node.elem[k] = nullptr;
1335  }
1336  }
1337 
1338  // copy active elements
1339  Element* e;
1340 
1341  for_all_active_elements(e, mesh)
1342  {
1343  Element* enew;
1344  Node *v0 = &nodes[e->vn[0]->id], *v1 = &nodes[e->vn[1]->id], *v2 = &nodes[e->vn[2]->id];
1345  Node *e0 = &nodes[e->en[0]->id], *e1 = &nodes[e->en[1]->id], *e2 = &nodes[e->en[2]->id];
1346  if (e->is_triangle())
1347  {
1348  // create a new_ element
1349  enew = elements.add();
1350  enew->active = 1;
1351  enew->marker = e->marker;
1352  enew->nvert = 3;
1353  enew->iro_cache = e->iro_cache;
1354  enew->cm = e->cm;
1355 
1356  // set vertex and edge node pointers
1357  enew->vn[0] = v0;
1358  enew->vn[1] = v1;
1359  enew->vn[2] = v2;
1360  enew->en[0] = e0;
1361  enew->en[1] = e1;
1362  enew->en[2] = e2;
1363  }
1364  else
1365  {
1366  // create a new_ element
1367  Node *v3 = &nodes[e->vn[3]->id];
1368  Node *e3 = &nodes[e->en[3]->id];
1369  enew = elements.add();
1370  enew->active = 1;
1371  enew->marker = e->marker;
1372  enew->nvert = 4;
1373  enew->iro_cache = e->iro_cache;
1374  enew->cm = e->cm;
1375  enew->parent = nullptr;
1376  enew->visited = false;
1377 
1378  // set vertex and edge node pointers
1379  enew->vn[0] = v0;
1380  enew->vn[1] = v1;
1381  enew->vn[2] = v2;
1382  enew->vn[3] = v3;
1383  enew->en[0] = e0;
1384  enew->en[1] = e1;
1385  enew->en[2] = e2;
1386  enew->en[3] = e3;
1387  }
1388 
1389  // copy edge markers
1390  for (unsigned int j = 0; j < e->get_nvert(); j++)
1391  {
1392  Node* en = MeshUtil::get_base_edge_node(e, j);
1393  enew->en[j]->bnd = en->bnd;
1394  enew->en[j]->marker = en->marker;
1395  }
1396 
1397  if (e->is_curved())
1398  enew->cm = new CurvMap(e->cm);
1399  }
1400 
1401  nbase = nactive = ninitial = mesh->nactive;
1402  ntopvert = mesh->ntopvert = get_num_nodes();
1403  seq = g_mesh_seq++;
1404  }
1405 
1406  void Mesh::convert_quads_to_triangles()
1407  {
1408  Element* e;
1409 
1410  elements.set_append_only(true);
1411  for_all_active_elements(e, this)
1412  refine_element_to_triangles_id(e->id);
1413  elements.set_append_only(false);
1414 
1415  MeshSharedPtr mesh_tmp_for_convert(new Mesh);
1416  mesh_tmp_for_convert->copy_converted(MeshSharedPtr(this));
1417 
1418  for (int i = 0; i < mesh_tmp_for_convert->ntopvert; i++)
1419  {
1420  if (mesh_tmp_for_convert->nodes[i].type == 1)
1421  {
1422  mesh_tmp_for_convert->nodes[i].y = 0.0;
1423  }
1424  }
1425  MeshReaderH2D loader_mesh_tmp_for_convert;
1426  char* mesh_file_tmp = nullptr;
1427  mesh_file_tmp = tmpnam(nullptr);
1428  loader_mesh_tmp_for_convert.save(mesh_file_tmp, mesh_tmp_for_convert);
1429  loader_mesh_tmp_for_convert.load(mesh_file_tmp, mesh_tmp_for_convert);
1430  remove(mesh_file_tmp);
1431  copy(mesh_tmp_for_convert);
1432  }
1433 
1434  void Mesh::convert_to_base()
1435  {
1436  Element* e;
1437 
1438  elements.set_append_only(true);
1439  for_all_active_elements(e, this)
1440  convert_element_to_base_id(e->id);
1441  elements.set_append_only(false);
1442 
1443  MeshSharedPtr mesh_tmp_for_convert(new Mesh);
1444  mesh_tmp_for_convert->copy_converted(MeshSharedPtr(this));
1445  for (int i = 0; i < mesh_tmp_for_convert->ntopvert; i++)
1446  {
1447  if (mesh_tmp_for_convert->nodes[i].type == 1)
1448  {
1449  mesh_tmp_for_convert->nodes[i].y = 0.0;
1450  }
1451  }
1452  MeshReaderH2D loader_mesh_tmp_for_convert;
1453  char* mesh_file_tmp = nullptr;
1454  mesh_file_tmp = tmpnam(nullptr);
1455  loader_mesh_tmp_for_convert.save(mesh_file_tmp, mesh_tmp_for_convert);
1456  loader_mesh_tmp_for_convert.load(mesh_file_tmp, mesh_tmp_for_convert);
1457  remove(mesh_file_tmp);
1458  copy(mesh_tmp_for_convert);
1459  }
1460 
1461  void Mesh::refine_triangle_to_quads(Element* e, Element** sons_out)
1462  {
1463  // remember the markers of the edge nodes
1464  int bnd[3] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd };
1465  int mrk[3] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker };
1466 
1467  // obtain three mid-edge and one gravity vertex nodes
1468  Node* x0 = this->get_vertex_node(e->vn[0]->id, e->vn[1]->id);
1469  Node* x1 = this->get_vertex_node(e->vn[1]->id, e->vn[2]->id);
1470  Node* x2 = this->get_vertex_node(e->vn[2]->id, e->vn[0]->id);
1471  Node* mid = this->get_vertex_node(x0->id, e->vn[1]->id);
1472 
1473  mid->x = (x0->x + x1->x + x2->x) / 3;
1474  mid->y = (x0->y + x1->y + x2->y) / 3;
1475 
1476  // check if element e is a internal element.
1477  bool e_inter = true;
1478  for (unsigned int n = 0; n < e->get_nvert(); n++)
1479  {
1480  if (bnd[n] == 1)
1481  e_inter = false;
1482  }
1483 
1484  CurvMap* cm[4];
1485  memset(cm, 0, sizeof(cm));
1486 
1487  // adjust mid-edge and gravity coordinates if this is a curved element
1488  if (e->is_curved())
1489  {
1490  if (!e_inter)
1491  {
1492  double2 pt[4] = { { 0.0, -1.0 }, { 0.0, 0.0 }, { -1.0, 0.0 }, { -0.33333333, -0.33333333 } };
1493  e->cm->get_mid_edge_points(e, pt, 4);
1494  x0->x = pt[0][0]; x0->y = pt[0][1];
1495  x1->x = pt[1][0]; x1->y = pt[1][1];
1496  x2->x = pt[2][0]; x2->y = pt[2][1];
1497  mid->x = pt[3][0]; mid->y = pt[3][1];
1498  }
1499  }
1500 
1501  // get the boundary edge angle.
1502  double refinement_angle[3] = { 0.0, 0.0, 0.0 };
1503  if (e->is_curved() && (!e_inter))
1504  {
1505  // for base element.
1506  Element* e_temp = e;
1507  double multiplier = 1.0;
1508  while (!e_temp->cm->toplevel)
1509  {
1510  e_temp = e_temp->parent;
1511  multiplier *= 2.0;
1512  }
1513 
1514  for (unsigned int n = 0; n < e->get_nvert(); n++)
1515  {
1516  if (e_temp->cm->curves[n] != nullptr && e_temp->cm->curves[n]->type == ArcType)
1517  refinement_angle[n] = ((Arc*)e_temp->cm->curves[n])->angle / multiplier;
1518  }
1519  }
1520 
1521  double angle2 = 0.0;
1522  int idx = 0;
1523  // create CurvMaps for sons if this is a curved element
1524  if ((e->is_curved()) && (!e_inter))
1525  {
1526  for (idx = 0; idx < 2; idx++)
1527  {
1528  if (e->cm->curves[idx] != nullptr)
1529  {
1530  cm[idx] = new CurvMap;
1531  memset(cm[idx], 0, sizeof(CurvMap));
1532  cm[idx + 1] = new CurvMap;
1533  memset(cm[idx + 1], 0, sizeof(CurvMap));
1534  }
1535  }
1536 
1537  idx = 0;
1538  if (e->cm->curves[idx] != nullptr)
1539  {
1540  angle2 = refinement_angle[0] / 2;
1541  Node* node_temp = this->get_vertex_node(e->vn[idx % 3]->id, e->vn[(idx + 1) % 3]->id);
1542 
1543  for (int k = 0; k < 2; k++)
1544  {
1545  int p1, p2;
1546  int idx2 = 0;
1547 
1548  if (k == 0)
1549  {
1550  p1 = e->vn[(idx) % 3]->id;
1551  p2 = node_temp->id;
1552  if (idx == 0) idx2 = 0;
1553  if (idx == 1) idx2 = 1;
1554  if (idx == 2) continue;
1555  }
1556  else
1557  {
1558  p1 = node_temp->id;
1559  p2 = e->vn[(idx + 1) % 3]->id;
1560  idx = (idx + 1) % 3;
1561  if (idx == 0) continue;
1562  if (idx == 1) idx2 = 0;
1563  if (idx == 2) idx2 = 0;
1564  }
1565 
1566  Arc* curve = new Arc(angle2);
1567 
1568  int inner = 1, outer = 0;
1569 
1570  curve->pt[0][0] = nodes[p1].x;
1571  curve->pt[0][1] = nodes[p1].y;
1572  curve->pt[0][2] = 1.0;
1573 
1574  curve->pt[2][0] = nodes[p2].x;
1575  curve->pt[2][1] = nodes[p2].y;
1576  curve->pt[2][2] = 1.0;
1577 
1578  double a = (180.0 - angle2) / 180.0 * M_PI;
1579 
1580  // generate one control point
1581  double x = 1.0 / tan(a * 0.5);
1582  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
1583  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
1584  curve->pt[1][2] = cos((M_PI - a) * 0.5);
1585 
1586  cm[idx]->toplevel = true;
1587  cm[idx]->order = 4;
1588  cm[idx]->curves[idx2] = curve;
1589  }
1590  }
1591 
1592  idx = 1;
1593  if (e->cm->curves[idx] != nullptr)
1594  {
1595  angle2 = refinement_angle[1] / 2;
1596  Node* node_temp = this->get_vertex_node(e->vn[idx % 3]->id, e->vn[(idx + 1) % 3]->id);
1597  for (int k = 0; k < 2; k++)
1598  {
1599  int p1, p2;
1600  int idx2 = 0;
1601  if (k == 0)
1602  {
1603  p1 = e->vn[(idx) % 3]->id;
1604  p2 = node_temp->id;
1605  if (idx == 0) idx2 = 0;
1606  if (idx == 1) idx2 = 1;
1607  if (idx == 2) continue;
1608  }
1609  else
1610  {
1611  p1 = node_temp->id;
1612  p2 = e->vn[(idx + 1) % 3]->id;
1613  idx = (idx + 1) % 3;
1614  if (idx == 0) continue;
1615  if (idx == 1) idx2 = 0;
1616  if (idx == 2) idx2 = 0;
1617  }
1618 
1619  Arc* curve = new Arc(angle2);
1620 
1621  int inner = 1, outer = 0;
1622 
1623  curve->pt[0][0] = nodes[p1].x;
1624  curve->pt[0][1] = nodes[p1].y;
1625  curve->pt[0][2] = 1.0;
1626 
1627  curve->pt[inner + 1][0] = nodes[p2].x;
1628  curve->pt[inner + 1][1] = nodes[p2].y;
1629  curve->pt[inner + 1][2] = 1.0;
1630 
1631  double a = (180.0 - angle2) / 180.0 * M_PI;
1632 
1633  // generate one control point
1634  double x = 1.0 / tan(a * 0.5);
1635  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
1636  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
1637  curve->pt[1][2] = cos((M_PI - a) * 0.5);
1638 
1639  cm[idx]->toplevel = true;
1640  cm[idx]->order = 4;
1641  cm[idx]->curves[idx2] = curve;
1642  }
1643  }
1644  }
1645 
1646  // create the four sons
1647  Element* sons[3];
1648  sons[0] = this->create_quad(e->marker, e->vn[0], x0, mid, x2, cm[0]);
1649  sons[1] = this->create_quad(e->marker, x0, e->vn[1], x1, mid, cm[1]);
1650  sons[2] = this->create_quad(e->marker, x1, e->vn[2], x2, mid, cm[2]);
1651 
1652  // update coefficients of curved reference mapping
1653  for (int i = 0; i < 3; i++)
1654  if (sons[i]->is_curved())
1655  sons[i]->cm->update_refmap_coeffs(sons[i]);
1656 
1657  // deactivate this element and unregister from its nodes
1658  e->active = 0;
1659  if (this != nullptr)
1660  {
1661  this->nactive += 2;
1662  e->unref_all_nodes(this);
1663  }
1664  // now the original edge nodes may no longer exist...
1665 
1666  // set correct boundary status and markers for the new_ nodes
1667  sons[0]->en[0]->bnd = bnd[0]; sons[0]->en[0]->marker = mrk[0];
1668  sons[0]->en[3]->bnd = bnd[2]; sons[0]->en[3]->marker = mrk[2];
1669  sons[1]->en[0]->bnd = bnd[0]; sons[1]->en[0]->marker = mrk[0];
1670  sons[1]->en[1]->bnd = bnd[1]; sons[1]->en[1]->marker = mrk[1];
1671  sons[2]->en[0]->bnd = bnd[1]; sons[2]->en[0]->marker = mrk[1];
1672  sons[2]->en[1]->bnd = bnd[2]; sons[2]->en[1]->marker = mrk[2];
1673 
1674  //set pointers to parent element for sons
1675  for (int i = 0; i < 3; i++)
1676  {
1677  if (sons[i] != nullptr)
1678  sons[i]->parent = e;
1679  }
1680 
1681  // copy son pointers (could not have been done earlier because of the union)
1682  memcpy(e->sons, sons, 3 * sizeof(Element*));
1683 
1684  // If sons_out != nullptr, copy son pointers there.
1685  if (sons_out != nullptr)
1686  {
1687  for (int i = 0; i < 3; i++) sons_out[i] = sons[i];
1688  }
1689  }
1690 
1691  void Mesh::refine_element_to_quads_id(int id)
1692  {
1693  Element* e = get_element(id);
1694  if (!e->used) throw Hermes::Exceptions::Exception("Invalid element id number.");
1695  if (!e->active) throw Hermes::Exceptions::Exception("Attempt to refine element #%d which has been refined already.", e->id);
1696 
1697  if (e->is_triangle())
1698  refine_triangle_to_quads(e);
1699  else
1700  refine_quad_to_quads(e);
1701 
1702  seq = g_mesh_seq++;
1703  }
1704 
1705  void Mesh::refine_quad_to_triangles(Element* e)
1706  {
1707  // remember the markers of the edge nodes
1708  int bnd[H2D_MAX_NUMBER_EDGES] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd, e->en[3]->bnd };
1709  int mrk[H2D_MAX_NUMBER_EDGES] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker, e->en[3]->marker };
1710 
1711  // deactivate this element and unregister from its nodes
1712  e->active = false;
1713  nactive--;
1714  e->unref_all_nodes(this);
1715 
1716  // if bcheck is true, it is default add a new_ edge between
1717  bool bcheck = true;
1718  // vn[0] and vn[2]
1719  double length_x_0_2 = (e->vn[0]->x - e->vn[2]->x)*(e->vn[0]->x - e->vn[2]->x);
1720  double length_x_1_3 = (e->vn[1]->x - e->vn[3]->x)*(e->vn[1]->x - e->vn[3]->x);
1721 
1722  double length_y_0_2 = (e->vn[0]->y - e->vn[2]->y)*(e->vn[0]->y - e->vn[2]->y);
1723  double length_y_1_3 = (e->vn[1]->y - e->vn[3]->y)*(e->vn[1]->y - e->vn[3]->y);
1724 
1725  if ((length_x_0_2 + length_y_0_2) > (length_x_1_3 + length_y_1_3))
1726  {
1727  bcheck = false;
1728  }
1729 
1730  double angle2;
1731  unsigned int idx;
1732  CurvMap* cm[2];
1733  memset(cm, 0, sizeof(cm));
1734 
1735  // create CurvMaps for sons if this is a curved element
1736  if (e->is_curved())
1737  {
1738  int i_case2 = 0;
1739  if (bcheck == true)
1740  {
1741  if ((e->cm->curves[0] != nullptr) || (e->cm->curves[1] != nullptr))
1742  {
1743  cm[0] = new CurvMap;
1744  memset(cm[0], 0, sizeof(CurvMap));
1745  }
1746  if ((e->cm->curves[2] != nullptr) || (e->cm->curves[3] != nullptr))
1747  {
1748  cm[1] = new CurvMap;
1749  memset(cm[1], 0, sizeof(CurvMap));
1750  }
1751  }
1752  else if (bcheck == false)
1753  {
1754  if ((e->cm->curves[1] != nullptr) || (e->cm->curves[2] != nullptr))
1755  {
1756  cm[0] = new CurvMap;
1757  memset(cm[0], 0, sizeof(CurvMap));
1758  }
1759  if ((e->cm->curves[3] != nullptr) || (e->cm->curves[0] != nullptr))
1760  {
1761  cm[1] = new CurvMap;
1762  memset(cm[1], 0, sizeof(CurvMap));
1763  }
1764  //switch to the shorter diagonal
1765  i_case2 = 1;
1766  }
1767 
1768  for (unsigned int k = 0; k < 2; k++)
1769  {
1770  for (idx = 0 + 2 * k; idx < 2 + 2 * k; idx++)
1771  {
1772  if (e->cm->curves[(idx + i_case2) % 4] != nullptr)
1773  {
1774  angle2 = ((Arc*)e->cm->curves[(idx + i_case2) % 4])->angle;
1775 
1776  int p1, p2;
1777 
1778  p1 = e->vn[(idx + i_case2) % 4]->id;
1779  //node_temp->id;
1780  p2 = e->vn[(idx + i_case2 + 1) % 4]->id;
1781 
1782  Arc* curve = new Arc(angle2);
1783 
1784  curve->pt[0][0] = nodes[p1].x;
1785  curve->pt[0][1] = nodes[p1].y;
1786  curve->pt[0][2] = 1.0;
1787 
1788  curve->pt[2][0] = nodes[p2].x;
1789  curve->pt[2][1] = nodes[p2].y;
1790  curve->pt[2][2] = 1.0;
1791 
1792  double a = (180.0 - angle2) / 180.0 * M_PI;
1793 
1794  // generate one control point
1795  double x = 1.0 / tan(a * 0.5);
1796  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
1797  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
1798  curve->pt[1][2] = cos((M_PI - a) * 0.5);
1799 
1800  cm[k]->toplevel = true;
1801  cm[k]->order = 4;
1802  cm[k]->curves[idx % 2] = curve;
1803  }
1804  }
1805  }
1806  }
1807 
1808  // create the four sons
1809  Element* sons[H2D_MAX_ELEMENT_SONS];
1810  if (bcheck == true)
1811  {
1812  sons[0] = this->create_triangle(e->marker, e->vn[0], e->vn[1], e->vn[2], cm[0]);
1813  sons[1] = this->create_triangle(e->marker, e->vn[2], e->vn[3], e->vn[0], cm[1]);
1814  sons[2] = nullptr;
1815  sons[3] = nullptr;
1816  }
1817  else
1818  {
1819  sons[0] = this->create_triangle(e->marker, e->vn[1], e->vn[2], e->vn[3], cm[0]);
1820  sons[1] = this->create_triangle(e->marker, e->vn[3], e->vn[0], e->vn[1], cm[1]);
1821  sons[2] = nullptr;
1822  sons[3] = nullptr;
1823  }
1824 
1825  // update coefficients of curved reference mapping
1826  for (int i = 0; i < 2; i++)
1827  {
1828  if (sons[i]->is_curved())
1829  {
1830  sons[i]->cm->update_refmap_coeffs(sons[i]);
1831  }
1832  }
1833  nactive += 2;
1834  // now the original edge nodes may no longer exist...
1835  // set correct boundary status and markers for the new_ nodes
1836  if (bcheck == true)
1837  {
1838  sons[0]->en[0]->bnd = bnd[0]; sons[0]->en[0]->marker = mrk[0];
1839  sons[0]->en[1]->bnd = bnd[1]; sons[0]->en[1]->marker = mrk[1];
1840  sons[0]->vn[1]->bnd = bnd[0];
1841 
1842  sons[1]->en[0]->bnd = bnd[2]; sons[1]->en[0]->marker = mrk[2];
1843  sons[1]->en[1]->bnd = bnd[3]; sons[1]->en[1]->marker = mrk[3];
1844  sons[1]->vn[2]->bnd = bnd[1];
1845  }
1846  else
1847  {
1848  sons[0]->en[0]->bnd = bnd[1]; sons[0]->en[0]->marker = mrk[1];
1849  sons[0]->en[1]->bnd = bnd[2]; sons[0]->en[1]->marker = mrk[2];
1850  sons[0]->vn[1]->bnd = bnd[1];
1851 
1852  sons[1]->en[0]->bnd = bnd[3]; sons[1]->en[0]->marker = mrk[3];
1853  sons[1]->en[1]->bnd = bnd[0]; sons[1]->en[1]->marker = mrk[0];
1854  sons[1]->vn[2]->bnd = bnd[0];
1855  }
1856 
1857  //set pointers to parent element for sons
1858  for (int i = 0; i < H2D_MAX_ELEMENT_SONS; i++)
1859  if (sons[i] != nullptr)
1860  sons[i]->parent = e;
1861 
1862  // copy son pointers (could not have been done earlier because of the union)
1863  memcpy(e->sons, sons, H2D_MAX_ELEMENT_SONS * sizeof(Element*));
1864  }
1865 
1866  void Mesh::refine_element_to_triangles_id(int id)
1867  {
1868  Element* e = get_element(id);
1869  if (!e->used) throw Hermes::Exceptions::Exception("Invalid element id number.");
1870  if (!e->active) throw Hermes::Exceptions::Exception("Attempt to refine element #%d which has been refined already.", e->id);
1871 
1872  if (e->is_triangle())
1873  return;
1874  else
1875  refine_quad_to_triangles(e);
1876 
1877  seq = g_mesh_seq++;
1878  }
1879 
1880  void Mesh::convert_element_to_base_id(int id)
1881  {
1882  Element* e = get_element(id);
1883  if (!e->used) throw Hermes::Exceptions::Exception("Invalid element id number.");
1884  if (!e->active) throw Hermes::Exceptions::Exception("Attempt to refine element #%d which has been refined already.", e->id);
1885 
1886  if (e->is_triangle())
1887  convert_triangles_to_base(e);
1888  else
1889  // FIXME:
1890  convert_quads_to_base(e);
1891 
1892  seq = g_mesh_seq++;
1893  }
1894 
1895  Mesh::MarkersConversion::MarkersConversion() : min_marker_unused(1)
1896  {
1897  }
1898 
1899  Mesh::MarkersConversion::StringValid::StringValid()
1900  {
1901  }
1902 
1903  Mesh::MarkersConversion::StringValid::StringValid(std::string marker, bool valid) : marker(marker), valid(valid)
1904  {
1905  }
1906 
1907  Mesh::MarkersConversion::IntValid::IntValid()
1908  {
1909  }
1910 
1911  Mesh::MarkersConversion::IntValid::IntValid(int marker, bool valid) : marker(marker), valid(valid)
1912  {
1913  }
1914 
1915  Mesh::ElementMarkersConversion::ElementMarkersConversion()
1916  {
1917  }
1918 
1919  Mesh::MarkersConversion::MarkersConversionType Mesh::ElementMarkersConversion::get_type() const
1920  {
1921  return HERMES_ELEMENT_MARKERS_CONVERSION;
1922  }
1923 
1924  Mesh::BoundaryMarkersConversion::BoundaryMarkersConversion()
1925  {
1926  }
1927 
1928  Mesh::MarkersConversion::MarkersConversionType Mesh::BoundaryMarkersConversion::get_type() const
1929  {
1930  return HERMES_BOUNDARY_MARKERS_CONVERSION;
1931  }
1932 
1933  const Mesh::ElementMarkersConversion &Mesh::get_element_markers_conversion() const
1934  {
1935  return element_markers_conversion;
1936  }
1937 
1938  const Mesh::BoundaryMarkersConversion &Mesh::get_boundary_markers_conversion() const
1939  {
1940  return boundary_markers_conversion;
1941  }
1942 
1943  Mesh::ElementMarkersConversion &Mesh::get_element_markers_conversion()
1944  {
1945  return element_markers_conversion;
1946  }
1947 
1948  Mesh::BoundaryMarkersConversion &Mesh::get_boundary_markers_conversion()
1949  {
1950  return boundary_markers_conversion;
1951  }
1952 
1954  {
1955  // First a check that the string value is not already present.
1956  std::map<std::string, int>::iterator it = conversion_table_inverse.find(user_marker);
1957  if (it != conversion_table_inverse.end())
1958  return it->second;
1959  conversion_table.insert(std::pair<int, std::string>(this->min_marker_unused, user_marker));
1960  conversion_table_inverse.insert(std::pair<std::string, int>(user_marker, this->min_marker_unused));
1961  return this->min_marker_unused++;
1962  }
1963 
1964  int Mesh::MarkersConversion::size() const
1965  {
1966  return this->conversion_table.size();
1967  }
1968 
1970  {
1971  if (internal_marker == H2D_DG_INNER_EDGE_INT)
1972  return StringValid(H2D_DG_INNER_EDGE, true);
1973 
1974  std::map<int, std::string>::const_iterator marker = conversion_table.find(internal_marker);
1975  if (marker == conversion_table.end())
1976  return StringValid("-999", false);
1977  else
1978  return StringValid(marker->second, true);
1979  }
1980 
1982  {
1983  if (user_marker == H2D_DG_INNER_EDGE)
1984  return IntValid(H2D_DG_INNER_EDGE_INT, true);
1985 
1986  std::map<std::string, int>::const_iterator marker = conversion_table_inverse.find(user_marker);
1987  if (marker == conversion_table_inverse.end())
1988  return IntValid(-999, false);
1989  else
1990  return IntValid(marker->second, true);
1991  }
1992 
1993  Mesh::CurvedException::CurvedException(int elementId) : elementId(elementId)
1994  {
1995  this->message << "Element id " << elementId << " is curved, this is not supported in this method.";
1996  }
1997 
1998  Mesh::CurvedException::CurvedException(const CurvedException & e)
1999  {
2000  this->message << e.message.str();
2001  elementId = e.elementId;
2002  }
2003 
2004  int Mesh::CurvedException::getElementId() const
2005  {
2006  return this->elementId;
2007  }
2008 
2009  void Mesh::convert_triangles_to_base(Element *e)
2010  {
2011  // remember the markers of the edge nodes
2012  int bnd[3] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd };
2013  int mrk[3] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker };
2014 
2015  // check if element e is a internal element.
2016  bool e_inter = true;
2017  for (unsigned int n = 0; n < e->get_nvert(); n++)
2018  {
2019  if (bnd[n] == 1)
2020  e_inter = false;
2021  }
2022 
2023  // get the boundary edge angle.
2024  double refinement_angle[3] = { 0.0, 0.0, 0.0 };
2025  if (e->is_curved() && (!e_inter))
2026  {
2027  // for base element.
2028  Element* e_temp = e;
2029  double multiplier = 1.0;
2030  while (!e_temp->cm->toplevel)
2031  {
2032  e_temp = e_temp->parent;
2033  multiplier *= 2.0;
2034  }
2035 
2036  for (unsigned int n = 0; n < e->get_nvert(); n++)
2037  {
2038  if (e_temp->cm->curves[n] != nullptr && e_temp->cm->curves[n]->type == ArcType)
2039  refinement_angle[n] = ((Arc*)e_temp->cm->curves[n])->angle / multiplier;
2040  }
2041  }
2042 
2043  // deactivate this element and unregister from its nodes
2044  e->active = false;
2045  e->unref_all_nodes(this);
2046 
2047  double angle2 = 0.0;
2048  int idx = 0;
2049  CurvMap* cm;
2050  memset(&cm, 0, sizeof(cm));
2051 
2052  // create CurvMaps for sons if this is a curved element
2053  if ((e->is_curved()) && (!e_inter))
2054  {
2055  cm = new CurvMap;
2056  memset(cm, 0, sizeof(CurvMap));
2057 
2058  for (idx = 0; idx < 3; idx++)
2059  if ((e->cm->curves[idx] != nullptr) && (bnd[idx] == 1))
2060  {
2061  angle2 = refinement_angle[idx];
2062  int p1, p2;
2063  p1 = e->en[idx]->p1;
2064  p2 = e->en[idx]->p2;
2065  if (p1 > p2) std::swap(p1, p2);
2066 
2067  Arc* curve = new Arc(angle2);
2068 
2069  curve->pt[0][0] = nodes[p1].x;
2070  curve->pt[0][1] = nodes[p1].y;
2071  curve->pt[0][2] = 1.0;
2072 
2073  curve->pt[2][0] = nodes[p2].x;
2074  curve->pt[2][1] = nodes[p2].y;
2075  curve->pt[2][2] = 1.0;
2076 
2077  double a = (180.0 - angle2) / 180.0 * M_PI;
2078 
2079  // generate one control point
2080  double x = 1.0 / tan(a * 0.5);
2081  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
2082  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
2083  curve->pt[1][2] = cos((M_PI - a) * 0.5);
2084 
2085  cm->toplevel = true;
2086  cm->order = 4;
2087  cm->curves[idx] = curve;
2088  }
2089  }
2090 
2091  // create a new_ element.
2092  Element* enew;
2093  Node *v0 = &nodes[e->vn[0]->id], *v1 = &nodes[e->vn[1]->id], *v2 = &nodes[e->vn[2]->id];
2094  enew = this->create_triangle(e->marker, v0, v1, v2, cm);
2095 
2096  if (enew->is_curved())
2097  {
2098  enew->cm->update_refmap_coeffs(enew);
2099  }
2100 
2101  // now the original edge nodes may no longer exist...
2102  // set correct boundary status and markers for the new_ nodes
2103  enew->en[0]->bnd = bnd[0];
2104  enew->en[1]->bnd = bnd[1];
2105  enew->en[2]->bnd = bnd[2];
2106  enew->en[0]->marker = mrk[0];
2107  enew->en[1]->marker = mrk[1];
2108  enew->en[2]->marker = mrk[2];
2109  enew->parent = e;
2110  }
2111 
2112  void Mesh::convert_quads_to_base(Element *e)
2113  {
2114  // remember the markers of the edge nodes
2115  int bnd[H2D_MAX_NUMBER_EDGES] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd, e->en[3]->bnd };
2116  int mrk[H2D_MAX_NUMBER_EDGES] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker, e->en[3]->marker };
2117 
2118  // check if element e is a internal element.
2119  bool e_inter = true;
2120  for (unsigned int n = 0; n < e->get_nvert(); n++)
2121  {
2122  if (bnd[n] == 1)
2123  e_inter = false;
2124  }
2125 
2126  // get the boundary edge angle.
2127  double refinement_angle[H2D_MAX_NUMBER_EDGES] = { 0.0, 0.0, 0.0, 0.0 };
2128  if (e->is_curved() && (!e_inter))
2129  {
2130  // for base element.
2131  Element* e_temp = e;
2132  double multiplier = 1.0;
2133  while (!e_temp->cm->toplevel)
2134  {
2135  e_temp = e_temp->parent;
2136  multiplier *= 2.0;
2137  }
2138 
2139  for (unsigned int n = 0; n < e->get_nvert(); n++)
2140  {
2141  if (e_temp->cm->curves[n] != nullptr && e_temp->cm->curves[n]->type == ArcType && (bnd[n] == 1))
2142  refinement_angle[n] = ((Arc*)e_temp->cm->curves[n])->angle / multiplier;
2143  }
2144  }
2145 
2146  // FIXME:
2147  if (rtb_aniso)
2148  for (unsigned int i = 0; i < e->get_nvert(); i++)
2149  refinement_angle[i] = refinement_angle[i] * 2;
2150 
2151  // deactivate this element and unregister from its nodes
2152  e->active = false;
2153  e->unref_all_nodes(this);
2154 
2155  double angle2 = 0.0;
2156  int idx = 0;
2157  CurvMap* cm;
2158  memset(&cm, 0, sizeof(cm));
2159 
2160  // create CurvMaps for sons if this is a curved element
2161  if ((e->is_curved()) && (!e_inter))
2162  {
2163  bool create_new = false;
2164  for (unsigned int i = 0; i < e->get_nvert(); i++)
2165  {
2166  if (fabs(refinement_angle[i] - 0.0) > 1e-4)
2167  {
2168  create_new = true;
2169  }
2170  }
2171 
2172  if (create_new)
2173 
2174  {
2175  cm = new CurvMap;
2176  memset(cm, 0, sizeof(CurvMap));
2177  }
2178 
2179  for (idx = 0; idx < 4; idx++)
2180  if (fabs(refinement_angle[idx] - 0.0) > 1e-4)
2181  {
2182  angle2 = refinement_angle[idx];
2183  int p1, p2;
2184  p1 = e->en[idx]->p1;
2185  p2 = e->en[idx]->p2;
2186  if (p1 > p2) std::swap(p1, p2);
2187 
2188  Arc* curve = new Arc(angle2);
2189 
2190  curve->pt[0][0] = nodes[p1].x;
2191  curve->pt[0][1] = nodes[p1].y;
2192  curve->pt[0][2] = 1.0;
2193 
2194  curve->pt[2][0] = nodes[p2].x;
2195  curve->pt[2][1] = nodes[p2].y;
2196  curve->pt[2][2] = 1.0;
2197 
2198  double a = (180.0 - angle2) / 180.0 * M_PI;
2199 
2200  // generate one control point
2201  double x = 1.0 / tan(a * 0.5);
2202  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
2203  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
2204  curve->pt[1][2] = cos((M_PI - a) * 0.5);
2205 
2206  cm->toplevel = true;
2207  cm->order = 4;
2208  cm->curves[idx] = curve;
2209  }
2210  }
2211 
2212  // create a new_ element.
2213  Element* enew;
2214  Node *v0 = &nodes[e->vn[0]->id], *v1 = &nodes[e->vn[1]->id], *v2 = &nodes[e->vn[2]->id], *v3 = &nodes[e->vn[3]->id];
2215  enew = this->create_quad(e->marker, v0, v1, v2, v3, cm);
2216 
2217  if (enew->is_curved())
2218  {
2219  enew->cm->update_refmap_coeffs(enew);
2220  }
2221 
2222  // now the original edge nodes may no longer exist...
2223  // set correct boundary status and markers for the new_ nodes
2224  enew->en[0]->bnd = bnd[0];
2225  enew->en[1]->bnd = bnd[1];
2226  enew->en[2]->bnd = bnd[2];
2227  enew->en[3]->bnd = bnd[3];
2228  enew->en[0]->marker = mrk[0];
2229  enew->en[1]->marker = mrk[1];
2230  enew->en[2]->marker = mrk[2];
2231  enew->en[3]->marker = mrk[3];
2232  enew->parent = e;
2233  }
2234 
2235  void Mesh::refine_quad_to_quads(Element* e, int refinement)
2236  {
2237  // remember the markers of the edge nodes
2238  int bnd[H2D_MAX_NUMBER_EDGES] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd, e->en[3]->bnd };
2239  int mrk[H2D_MAX_NUMBER_EDGES] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker, e->en[3]->marker };
2240 
2241  // check if element e is a internal element.
2242  bool e_inter = true;
2243  for (unsigned int n = 0; n < e->get_nvert(); n++)
2244  {
2245  if (bnd[n] == 1)
2246  e_inter = false;
2247  }
2248 
2249  // get the boundary edge angle.
2250  double refinement_angle[H2D_MAX_NUMBER_EDGES] = { 0.0, 0.0, 0.0, 0.0 };
2251  if (e->is_curved() && (!e_inter))
2252  {
2253  // for base element.
2254  Element* e_temp = e;
2255  double multiplier = 1.0;
2256  while (!e_temp->cm->toplevel)
2257  {
2258  e_temp = e_temp->parent;
2259  multiplier *= 2.0;
2260  }
2261 
2262  for (unsigned int n = 0; n < e->get_nvert(); n++)
2263  {
2264  if (e_temp->cm->curves[n] != nullptr && e_temp->cm->curves[n]->type == ArcType && (bnd[n] == 1))
2265  refinement_angle[n] = ((Arc*)e_temp->cm->curves[n])->angle / multiplier;
2266  }
2267  }
2268 
2269  // deactivate this element and unregister from its nodes
2270  e->active = false;
2271  this->nactive--;
2272  e->unref_all_nodes(this);
2273 
2274  double angle2 = 0.0;
2275  int i, j;
2276  int idx = 0;
2277  Element* sons[H2D_MAX_ELEMENT_SONS] = { nullptr, nullptr, nullptr, nullptr };
2278  CurvMap* cm[H2D_MAX_ELEMENT_SONS];
2279  memset(cm, 0, sizeof(cm));
2280 
2281  // default refinement: one quad to four quads
2282  if (refinement == 0)
2283  {
2284  // obtain four mid-edge vertex nodes and one mid-element vetex node
2285  Node* x0 = get_vertex_node(e->vn[0]->id, e->vn[1]->id);
2286  Node* x1 = get_vertex_node(e->vn[1]->id, e->vn[2]->id);
2287  Node* x2 = get_vertex_node(e->vn[2]->id, e->vn[3]->id);
2288  Node* x3 = get_vertex_node(e->vn[3]->id, e->vn[0]->id);
2289  Node* mid = get_vertex_node(x0->id, x2->id);
2290 
2291  // adjust mid-edge coordinates if this is a curved element
2292  if (e->is_curved())
2293  {
2294  double2 pt[5] = { { 0.0, -1.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { -1.0, 0.0 }, { 0.0, 0.0 } };
2295  e->cm->get_mid_edge_points(e, pt, 5);
2296  x0->x = pt[0][0]; x0->y = pt[0][1];
2297  x1->x = pt[1][0]; x1->y = pt[1][1];
2298  x2->x = pt[2][0]; x2->y = pt[2][1];
2299  x3->x = pt[3][0]; x3->y = pt[3][1];
2300  mid->x = pt[4][0]; mid->y = pt[4][1];
2301  }
2302 
2303  // create CurvMaps for sons.
2304  if ((e->is_curved()) && (!e_inter))
2305  {
2306  //bool create_new_ = false;
2307  for (unsigned int i = 0; i < e->get_nvert(); i++)
2308  {
2309  if (fabs(refinement_angle[i] - 0.0) > 1e-4)
2310  {
2311  cm[i % 4] = new CurvMap;
2312  memset(cm[i % 4], 0, sizeof(CurvMap));
2313  cm[(i + 1) % 4] = new CurvMap;
2314  memset(cm[(i + 1) % 4], 0, sizeof(CurvMap));
2315  }
2316  }
2317 
2318  for (idx = 0; idx < 4; idx++)
2319  if (cm[idx] != nullptr)
2320  {
2321  if ((fabs(refinement_angle[idx % 4] - 0.0) > 1e-4))
2322  {
2323  angle2 = refinement_angle[idx % 4] / 2;
2324  Node* node_temp = this->get_vertex_node(e->vn[idx % 4]->id, e->vn[(idx + 1) % 4]->id);
2325 
2326  int p1, p2;
2327  p1 = e->vn[(idx) % 4]->id;
2328  p2 = node_temp->id;
2329 
2330  Arc* curve = new Arc(angle2);
2331 
2332  curve->pt[0][0] = nodes[p1].x;
2333  curve->pt[0][1] = nodes[p1].y;
2334  curve->pt[0][2] = 1.0;
2335 
2336  curve->pt[2][0] = nodes[p2].x;
2337  curve->pt[2][1] = nodes[p2].y;
2338  curve->pt[2][2] = 1.0;
2339 
2340  double a = (180.0 - angle2) / 180.0 * M_PI;
2341 
2342  // generate one control point
2343  double x = 1.0 / tan(a * 0.5);
2344  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
2345  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
2346  curve->pt[1][2] = cos((M_PI - a) * 0.5);
2347 
2348  cm[idx]->toplevel = true;
2349  cm[idx]->order = 4;
2350  cm[idx]->curves[idx % 4] = curve;
2351  }
2352 
2353  if ((fabs(refinement_angle[(idx + 3) % 4] - 0.0) > 1e-4))
2354  {
2355  angle2 = refinement_angle[(idx + 3) % 4] / 2;
2356  Node* node_temp = this->get_vertex_node(e->vn[idx % 4]->id, e->vn[(idx + 1) % 4]->id);
2357 
2358  int p1, p2;
2359  p1 = e->vn[(idx) % 4]->id;
2360  p2 = node_temp->id;
2361 
2362  Arc* curve = new Arc(angle2);
2363 
2364  curve->pt[0][0] = nodes[p1].x;
2365  curve->pt[0][1] = nodes[p1].y;
2366  curve->pt[0][2] = 1.0;
2367 
2368  curve->pt[2][0] = nodes[p2].x;
2369  curve->pt[2][1] = nodes[p2].y;
2370  curve->pt[2][2] = 1.0;
2371 
2372  double a = (180.0 - angle2) / 180.0 * M_PI;
2373 
2374  // generate one control point
2375  double x = 1.0 / tan(a * 0.5);
2376  curve->pt[1][0] = 0.5*((curve->pt[2][0] + curve->pt[0][0]) + (curve->pt[2][1] - curve->pt[0][1]) * x);
2377  curve->pt[1][1] = 0.5*((curve->pt[2][1] + curve->pt[0][1]) - (curve->pt[2][0] - curve->pt[0][0]) * x);
2378  curve->pt[1][2] = cos((M_PI - a) * 0.5);
2379 
2380  cm[idx]->toplevel = true;
2381  cm[idx]->order = 4;
2382  cm[idx]->curves[(idx + 3) % 4] = curve;
2383  }
2384  }
2385  }
2386 
2387  // create the four sons
2388  sons[0] = this->create_quad(e->marker, e->vn[0], x0, mid, x3, cm[0]);
2389  sons[1] = this->create_quad(e->marker, x0, e->vn[1], x1, mid, cm[1]);
2390  sons[2] = this->create_quad(e->marker, mid, x1, e->vn[2], x2, cm[2]);
2391  sons[3] = this->create_quad(e->marker, x3, mid, x2, e->vn[3], cm[3]);
2392 
2393  // Increase the number of active elements by 4.
2394  this->nactive += 4;
2395 
2396  // set correct boundary markers for the new_ edge nodes
2397  for (i = 0; i < 4; i++)
2398  {
2399  j = (i > 0) ? i - 1 : 3;
2400  sons[i]->en[j]->bnd = bnd[j]; sons[i]->en[j]->marker = mrk[j];
2401  sons[i]->en[i]->bnd = bnd[i]; sons[i]->en[i]->marker = mrk[i];
2402  sons[i]->vn[j]->bnd = bnd[j];
2403  }
2404  }
2405  else assert(0);
2406 
2407  // update coefficients of curved reference mapping
2408  for (i = 0; i < 4; i++)
2409  if (sons[i] != nullptr && sons[i]->cm != nullptr)
2410  sons[i]->cm->update_refmap_coeffs(sons[i]);
2411 
2412  //set pointers to parent element for sons
2413  for (int i = 0; i < 4; i++)
2414  if (sons[i] != nullptr)
2415  sons[i]->parent = e;
2416 
2417  // copy son pointers (could not have been done earlier because of the union)
2418  memcpy(e->sons, sons, sizeof(sons));
2419  }
2420 
2421  int Mesh::get_edge_degree(Node* v1, Node* v2)
2422  {
2423  int degree = 0;
2424  Node* v3 = this->peek_vertex_node(v1->id, v2->id);
2425  if (v3 != nullptr)
2426  {
2427  degree = 1 + std::max(get_edge_degree(v1, v3), get_edge_degree(v3, v2));
2428  }
2429  return degree;
2430  }
2431 
2432  void Mesh::regularize_triangle(Element* e)
2433  {
2434  int i, k, k1, k2;
2435 
2436  Element* t[3];
2437 
2438  int eo[3] = { get_edge_degree(e->vn[0], e->vn[1]),
2439  get_edge_degree(e->vn[1], e->vn[2]),
2440  get_edge_degree(e->vn[2], e->vn[0]) };
2441 
2442  int sum = eo[0] + eo[1] + eo[2];
2443  if (sum == 3)
2444  {
2445  refine_element_id(e->id);
2446  }
2447  else if (sum > 0)
2448  {
2449  // remember the markers of the edge nodes
2450  int bnd[3] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd };
2451  int mrk[3] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker };
2452 
2453  if (sum == 1)
2454  {
2455  Node* v4;
2456  for (i = 0; i < 3; i++)
2457  if (eo[i] == 1) k = i;
2458  k1 = e->next_vert(k);
2459  k2 = e->prev_vert(k);
2460  v4 = peek_vertex_node(e->vn[k]->id, e->vn[k1]->id);
2461 
2462  e->active = 0;
2463  nactive += 1;
2464  e->unref_all_nodes(this);
2465 
2466  t[0] = this->create_triangle(e->marker, e->vn[k], v4, e->vn[k2], nullptr);
2467  t[1] = this->create_triangle(e->marker, v4, e->vn[k1], e->vn[k2], nullptr);
2468 
2469  // set correct boundary status and markers for the new_ nodes
2470  t[0]->en[2]->bnd = bnd[k2];
2471  t[1]->en[1]->bnd = bnd[k1];
2472  t[0]->en[2]->marker = mrk[k2];
2473  t[1]->en[1]->marker = mrk[k1];
2474 
2475  e->sons[0] = t[0];
2476  e->sons[1] = t[1];
2477  e->sons[2] = nullptr;
2478  e->sons[3] = nullptr;
2479  }
2480  else if (sum == 2)
2481  {
2482  Node *v4, *v5;
2483  for (i = 0; i < 3; i++)
2484  if (eo[i] == 0) k = i;
2485  k1 = e->next_vert(k);
2486  k2 = e->prev_vert(k);
2487  v4 = peek_vertex_node(e->vn[k1]->id, e->vn[k2]->id);
2488  v5 = peek_vertex_node(e->vn[k2]->id, e->vn[k]->id);
2489 
2490  e->active = 0;
2491  nactive += 2;
2492  e->unref_all_nodes(this);
2493 
2494  t[0] = this->create_triangle(e->marker, e->vn[k], e->vn[k1], v4, nullptr);
2495  t[1] = this->create_triangle(e->marker, v4, v5, e->vn[k], nullptr);
2496  t[2] = this->create_triangle(e->marker, v4, e->vn[k2], v5, nullptr);
2497 
2498  // set correct boundary status and markers for the new_ nodes
2499  t[0]->en[0]->bnd = bnd[k];
2500  t[0]->en[0]->marker = mrk[k];
2501 
2502  e->sons[0] = t[0];
2503  e->sons[1] = t[1];
2504  e->sons[2] = t[2];
2505  e->sons[3] = nullptr;
2506  }
2507  }
2508 
2509  // store id of parent
2510  if (!e->active)
2511  {
2512  for (i = 0; i < 4; i++)
2513  assign_parent(e, i);
2514  }
2515  }
2516 
2517  void Mesh::regularize_quad(Element* e)
2518  {
2519  int i, k = 0, k1, k2, k3, n = 0, m = 0;
2520  Node *v4, *v5;
2521  Element* t[4];
2522 
2523  int eo[4] = { get_edge_degree(e->vn[0], e->vn[1]),
2524  get_edge_degree(e->vn[1], e->vn[2]),
2525  get_edge_degree(e->vn[2], e->vn[3]),
2526  get_edge_degree(e->vn[3], e->vn[0]) };
2527 
2528  int sum = eo[0] + eo[1] + eo[2] + eo[3];
2529  if (sum == 4)
2530  {
2531  refine_element_id(e->id);
2532  }
2533  else if (sum > 0)
2534  {
2535  // remember the markers of the edge nodes
2536  int bnd[H2D_MAX_NUMBER_EDGES] = { e->en[0]->bnd, e->en[1]->bnd, e->en[2]->bnd, e->en[3]->bnd };
2537  int mrk[H2D_MAX_NUMBER_EDGES] = { e->en[0]->marker, e->en[1]->marker, e->en[2]->marker, e->en[3]->marker };
2538 
2539  if (sum == 1)
2540  {
2541  for (i = 0; i < 4; i++)
2542  if (eo[i] == 1) k = i;
2543  k1 = e->next_vert(k);
2544  k2 = e->next_vert(k1);
2545  k3 = e->prev_vert(k);
2546  v4 = peek_vertex_node(e->vn[k]->id, e->vn[k1]->id);
2547 
2548  e->active = 0;
2549  nactive += 2;
2550  e->unref_all_nodes(this);
2551 
2552  t[0] = this->create_triangle(e->marker, e->vn[k], v4, e->vn[k3], nullptr);
2553  t[1] = this->create_triangle(e->marker, v4, e->vn[k1], e->vn[k2], nullptr);
2554  t[2] = this->create_triangle(e->marker, v4, e->vn[k2], e->vn[k3], nullptr);
2555 
2556  // set correct boundary status and markers for the new_ nodes
2557  t[0]->en[2]->bnd = bnd[k3];
2558  t[1]->en[1]->bnd = bnd[k1];
2559  t[2]->en[1]->bnd = bnd[k2];
2560  t[0]->en[2]->marker = mrk[k3];
2561  t[1]->en[1]->marker = mrk[k1];
2562  t[2]->en[1]->marker = mrk[k2];
2563 
2564  e->sons[0] = t[0];
2565  e->sons[1] = t[1];
2566  e->sons[2] = t[2];
2567  e->sons[3] = nullptr;
2568  }
2569  else if (sum == 2)
2570  {
2571  // two hanging nodes opposite to each other
2572  if (eo[0] == 1 && eo[2] == 1) refine_element_id(e->id, 2);
2573  else if (eo[1] == 1 && eo[3] == 1) refine_element_id(e->id, 1);
2574  else // two hanging nodes next to each other
2575  {
2576  for (i = 0; i < 4; i++)
2577  if (eo[i] == 1 && eo[e->next_vert(i)] == 1) k = i;
2578  k1 = e->next_vert(k);
2579  k2 = e->next_vert(k1);
2580  k3 = e->prev_vert(k);
2581  v4 = peek_vertex_node(e->vn[k]->id, e->vn[k1]->id);
2582  v5 = peek_vertex_node(e->vn[k1]->id, e->vn[k2]->id);
2583 
2584  e->active = 0;
2585  nactive += 3;
2586  e->unref_all_nodes(this);
2587 
2588  t[0] = this->create_triangle(e->marker, e->vn[k1], v5, v4, nullptr);
2589  t[1] = this->create_triangle(e->marker, v5, e->vn[k2], e->vn[k3], nullptr);
2590  t[2] = this->create_triangle(e->marker, v4, v5, e->vn[k3], nullptr);
2591  t[3] = this->create_triangle(e->marker, v4, e->vn[k3], e->vn[k], nullptr);
2592 
2593  t[1]->en[1]->bnd = bnd[k2];
2594  t[3]->en[1]->bnd = bnd[k3];
2595  t[1]->en[1]->marker = mrk[k2];
2596  t[3]->en[1]->marker = mrk[k3];
2597 
2598  e->sons[0] = t[0];
2599  e->sons[1] = t[1];
2600  e->sons[2] = t[2];
2601  e->sons[3] = t[3];
2602  }
2603  }
2604  else //sum = 3
2605  {
2606  if (eo[0] == 1 && eo[2] == 1)
2607  {
2608  refine_element_id(e->id, 2);
2609  for (i = 0; i < 4; i++)
2610  assign_parent(e, i);
2611  n = 2; m = 3;
2612  }
2613  else if (eo[1] == 1 && eo[3] == 1)
2614  {
2615  refine_element_id(e->id, 1);
2616  for (i = 0; i < 4; i++)
2617  assign_parent(e, i);
2618  n = 0; m = 1;
2619  }
2620 
2621  regularize_quad(e->sons[n]);
2622  regularize_quad(e->sons[m]);
2623  }
2624  }
2625 
2626  // store id of parent
2627  if (!e->active)
2628  {
2629  for (i = 0; i < 4; i++)
2630  assign_parent(e, i);
2631  }
2632  }
2633 
2634  void Mesh::flatten()
2635  {
2636  Node* node;
2637  for_all_edge_nodes(node, this)
2638  {
2639  if (node->elem[0] != nullptr) node->elem[0] = (Element*)(node->elem[0]->id + 1);
2640  if (node->elem[1] != nullptr) node->elem[1] = (Element*)(node->elem[1]->id + 1);
2641  }
2642 
2643  int* idx = new int[elements.get_size() + 1];
2644  Array<Element> new_elements;
2645  Element* e;
2646  for_all_active_elements(e, this)
2647  {
2648  Element* ee = new_elements.add();
2649  int temp = ee->id;
2650  *ee = *e;
2651  ee->id = temp;
2652  idx[e->id] = temp;
2653  parents[ee->id] = parents[e->id];
2654  }
2655 
2656  elements.copy(new_elements);
2657  nbase = nactive = elements.get_num_items();
2658 
2659  for_all_edge_nodes(node, this)
2660  {
2661  if (node->elem[0] != nullptr) node->elem[0] = &(elements[idx[((int)(long)node->elem[0]) - 1]]);
2662  if (node->elem[1] != nullptr) node->elem[1] = &(elements[idx[((int)(long)node->elem[1]) - 1]]);
2663  }
2664 
2665  delete[] idx;
2666  }
2667 
2668  void Mesh::assign_parent(Element* e, int i)
2669  {
2670  if (e->sons[i] != nullptr)
2671  {
2672  if (e->sons[i]->id >= parents_size)
2673  {
2674  parents_size = 2 * parents_size;
2675  parents = (int*)realloc(parents, sizeof(int)* parents_size);
2676  }
2677 
2678  parents[e->sons[i]->id] = parents[e->id];
2679  }
2680  }
2681 
2682  int* Mesh::regularize(int n)
2683  {
2684  int j;
2685  bool ok;
2686  bool reg = false;
2687  Element* e;
2688 
2689  if (n < 1)
2690  {
2691  n = 1;
2692  reg = true;
2693  }
2694 
2695  parents_size = 2 * get_max_element_id();
2696  parents = malloc_with_check<int>(parents_size);
2697  for_all_active_elements(e, this)
2698  parents[e->id] = e->id;
2699 
2700  do
2701  {
2702  ok = true;
2703  for_all_active_elements(e, this)
2704  {
2705  int iso = -1;
2706  if (e->is_triangle())
2707  {
2708  for (unsigned int i = 0; i < e->get_nvert(); i++)
2709  {
2710  j = e->next_vert(i);
2711  if (get_edge_degree(e->vn[i], e->vn[j]) > n)
2712  {
2713  iso = 0; ok = false; break;
2714  }
2715  }
2716  }
2717  else
2718  {
2719  if (((get_edge_degree(e->vn[0], e->vn[1]) > n) || (get_edge_degree(e->vn[2], e->vn[3]) > n))
2720  && (get_edge_degree(e->vn[1], e->vn[2]) <= n) && (get_edge_degree(e->vn[3], e->vn[0]) <= n))
2721  {
2722  iso = 2; ok = false;
2723  }
2724  else if ((get_edge_degree(e->vn[0], e->vn[1]) <= n) && (get_edge_degree(e->vn[2], e->vn[3]) <= n)
2725  && ((get_edge_degree(e->vn[1], e->vn[2]) > n) || (get_edge_degree(e->vn[3], e->vn[0]) > n)))
2726  {
2727  iso = 1; ok = false;
2728  }
2729  else
2730  {
2731  for (unsigned int i = 0; i < e->get_nvert(); i++)
2732  {
2733  j = e->next_vert(i);
2734  if (get_edge_degree(e->vn[i], e->vn[j]) > n)
2735  {
2736  iso = 0; ok = false; break;
2737  }
2738  }
2739  }
2740  }
2741 
2742  if (iso >= 0)
2743  {
2744  refine_element_id(e->id, iso);
2745  for (int i = 0; i < 4; i++)
2746  assign_parent(e, i);
2747  }
2748  }
2749  } while (!ok);
2750 
2751  if (reg)
2752  {
2753  for_all_active_elements(e, this)
2754  {
2755  if (e->is_curved()) throw Hermes::Exceptions::Exception("Regularization of curved elements is not supported.");
2756 
2757  if (e->is_triangle())
2758  regularize_triangle(e);
2759  else
2760  regularize_quad(e);
2761  }
2762  flatten();
2763  }
2764 
2765  return parents;
2766  }
2767 
2768  const std::string EggShell::eggShellInnerMarker = "Eggshell-inner";
2769  const std::string EggShell::eggShell1Marker = "Eggshell-1";
2770  const std::string EggShell::eggShell0Marker = "Eggshell-0";
2771  const std::string EggShell::eggShellMarker = "Eggshell";
2772  bool EggShell::egg_shell_verbose = false;
2773 
2774  MeshSharedPtr EggShell::get_egg_shell(MeshSharedPtr mesh, std::string marker, unsigned int levels)
2775  {
2776  if (levels < 2)
2777  {
2778  throw Hermes::Exceptions::ValueException("levels", levels, 2);
2779  return MeshSharedPtr(new Mesh());
2780  }
2781  std::vector<std::string> markers;
2782  markers.push_back(marker);
2783  return get_egg_shell(mesh, markers, levels);
2784  }
2785 
2786  MeshSharedPtr EggShell::get_egg_shell(MeshSharedPtr mesh, std::vector<std::string> markers, unsigned int levels)
2787  {
2788  if (levels < 2)
2789  {
2790  throw Hermes::Exceptions::ValueException("levels", levels, 2);
2791  return MeshSharedPtr(new Mesh);
2792  }
2793 
2794  MeshSharedPtr target_mesh(new Mesh);
2795  target_mesh->copy(mesh);
2796 
2797  int eggShell_marker_0 = target_mesh->get_boundary_markers_conversion().insert_marker(eggShell0Marker);
2798  int eggShell_marker_1 = target_mesh->get_boundary_markers_conversion().insert_marker(eggShell1Marker);
2799  int eggShell_marker_inner = target_mesh->get_boundary_markers_conversion().insert_marker(eggShellInnerMarker);
2800  int eggShell_marker_volume = target_mesh->get_element_markers_conversion().insert_marker(eggShellMarker);
2801 
2802  // Search for the adjacent element with the basic logic + vertex-based lookup.
2803  // This only:
2804  // - fills the "1" marker where appropriate
2805  // - fills the volumetric marker
2806  get_egg_shell_structures(target_mesh, markers, levels);
2807 
2808  // Fix hanging nodes.
2809  // This only:
2810  // - adds the volumetric marker where necessary
2811  EggShell::fix_hanging_nodes(target_mesh);
2812 
2813  Element* e;
2814 
2815  /*
2816  bool elements_added;
2817  // Fill holes.
2818  while (true)
2819  {
2820  elements_added = false;
2821  for_all_active_elements(e, target_mesh)
2822  {
2823  NeighborSearch<double> ns(e, target_mesh);
2824  ns.set_ignore_errors(true);
2825  int edges_eggShell = 0;
2826  for (int edge = 0; edge < e->get_nvert(); edge++)
2827  {
2828  // This has been taken care of above.
2829  if (e->en[edge]->marker == eggShell_marker_1 || e->en[edge]->bnd)
2830  continue;
2831 
2832  ns.set_active_edge(edge);
2833  for (int neighbor = 0; neighbor < ns.get_num_neighbors(); neighbor++)
2834  {
2835  Element* neighbor_el = ns.get_neighb_el();
2836  if (neighbor_el && neighbor_el->marker == eggShell_marker_volume)
2837  {
2838  edges_eggShell++;
2839  break;
2840  }
2841  }
2842  }
2843  if (edges_eggShell > 2)
2844  {
2845  e->marker = eggShell_marker_volume;
2846  elements_added = true;
2847  }
2848  }
2849  if (elements_added)
2850  EggShell::fix_hanging_nodes(target_mesh);
2851  else
2852  break;
2853  }
2854  */
2855 
2856  // Mark used / not used elements according to the marker.
2857  for_all_active_elements(e, target_mesh)
2858  {
2859  e->used = false;
2860  Element* elem = e;
2861  while (elem->parent)
2862  {
2863  elem->parent->used = false;
2864  elem = elem->parent;
2865  }
2866  }
2867 
2868  for_all_elements(e, target_mesh)
2869  {
2870  if (e->marker == eggShell_marker_volume)
2871  {
2872  e->used = true;
2873  Element* elem = e;
2874  while (elem->parent)
2875  {
2876  elem->parent->used = true;
2877  elem = elem->parent;
2878  }
2879  }
2880  }
2881 
2882  // Now mark the boundaries + calculate active elements.
2883  target_mesh->nactive = 0;
2884  for_all_active_elements(e, target_mesh)
2885  {
2886  target_mesh->nactive++;
2887  NeighborSearch<double> ns(e, target_mesh);
2888  ns.set_ignore_errors(true);
2889  for (int edge = 0; edge < e->get_nvert(); edge++)
2890  {
2891  // This has been taken care of above.
2892  if (e->en[edge]->marker == eggShell_marker_1 || e->en[edge]->bnd)
2893  continue;
2894 
2895  // Find out if all neighbors are eggShell (should be).
2896  bool neighbors_eggshell = false;
2897  ns.set_active_edge(edge);
2898  for (int neighbor = 0; neighbor < ns.get_num_neighbors(); neighbor++)
2899  {
2900  Element* neighbor_el = ns.get_neighb_el();
2901  if (neighbors_eggshell)
2902  assert(neighbor_el->marker == eggShell_marker_volume);
2903  else if (neighbor_el->marker == eggShell_marker_volume)
2904  neighbors_eggshell = true;
2905 
2906  if (neighbors_eggshell)
2907  {
2908  e->en[edge]->marker = eggShell_marker_inner;
2909  neighbor_el->en[ns.get_neighbor_edge().local_num_of_edge]->marker = eggShell_marker_inner;
2910  }
2911  else if (e->en[edge]->marker != eggShell_marker_1)
2912  {
2913  e->en[edge]->marker = eggShell_marker_0;
2914  }
2915  }
2916  }
2917 
2918  for_all_active_elements(e, target_mesh)
2919  {
2920  for (int edge = 0; edge < e->get_nvert(); edge++)
2921  {
2922  if (e->en[edge]->marker == eggShell_marker_0 || e->en[edge]->marker == eggShell_marker_1)
2923  {
2924  e->en[edge]->bnd = true;
2925  e->vn[edge]->bnd = true;
2926  e->vn[(edge + 1) % e->get_nvert()]->bnd = true;
2927  }
2928  else if (e->en[edge]->bnd)
2929  {
2930  e->en[edge]->marker = eggShell_marker_0;
2931  }
2932  }
2933  }
2934  }
2935 
2936  fix_markers(target_mesh, mesh);
2937 
2938  return target_mesh;
2939  }
2940 
2941  void EggShell::get_egg_shell_structures(MeshSharedPtr target_mesh, std::vector<std::string> markers, unsigned int levels)
2942  {
2943  // Check.
2944  if (levels < 1)
2945  throw Exceptions::ValueException("levels", levels, 1);
2946 
2947  int eggShell_marker_1 = target_mesh->get_boundary_markers_conversion().get_internal_marker(eggShell1Marker).marker;
2948  int eggShell_marker_volumetric = target_mesh->get_element_markers_conversion().get_internal_marker(eggShellMarker).marker;
2949 
2950  std::vector<int> internal_markers;
2951  for (int i = 0; i < markers.size(); i++)
2952  {
2953  Hermes::Hermes2D::Mesh::MarkersConversion::IntValid internalMarker = target_mesh->get_element_markers_conversion().get_internal_marker(markers[i]);
2954  if (internalMarker.valid)
2955  internal_markers.push_back(internalMarker.marker);
2956  else
2957  throw Exceptions::Exception("Marker %s not valid in target_mesh::get_egg_shell.", markers[i].c_str());
2958  }
2959 
2960  // Initial setup.
2961  int* neighbors_target = calloc_with_check<int>(target_mesh->get_max_element_id());
2962  int* neighbor_targets_local = calloc_with_check<int>(target_mesh->get_max_element_id());
2963  Element* e;
2964  for_all_active_elements(e, target_mesh)
2965  {
2966  bool target_marker = false;
2967  for (int i = 0; i < internal_markers.size(); i++)
2968  {
2969  if (e->marker == internal_markers[i])
2970  {
2971  target_marker = true;
2972  break;
2973  }
2974  }
2975  if (target_marker)
2976  neighbor_targets_local[e->id] = 1;
2977  }
2978 
2979  // And calculation.
2980  for (int level = 1; level <= levels; level++)
2981  {
2982  memcpy(neighbors_target, neighbor_targets_local, target_mesh->get_max_element_id() * sizeof(int));
2983  for_all_active_elements(e, target_mesh)
2984  {
2985  if (neighbors_target[e->id] == level)
2986  {
2987  NeighborSearch<double> ns(e, target_mesh);
2988  for (int edge = 0; edge < e->get_nvert(); edge++)
2989  {
2990  // Vertices handling.
2991  if (level == 1)
2992  handle_vertex_on_target_mesh(e, edge, target_mesh, internal_markers, neighbor_targets_local);
2993 
2994  if (e->en[edge]->bnd)
2995  continue;
2996 
2997  ns.set_active_edge(edge);
2998  for (int neighbor = 0; neighbor < ns.get_num_neighbors(); neighbor++)
2999  {
3000  ns.set_active_segment(neighbor);
3001  Element* neighbor_el = ns.get_neighb_el();
3002 
3003  // The neighbor has been already visited.
3004  // This respects the vertex-based lookup, because that had already set the value.
3005  if (neighbor_targets_local[neighbor_el->id] > 0 && level > 1)
3006  continue;
3007 
3008  // Mark the appropriate boundary as "1".
3009  if (level == 1)
3010  {
3011  e->en[edge]->marker = eggShell_marker_1;
3012  neighbor_el->en[ns.get_neighbor_edge().local_num_of_edge]->marker = eggShell_marker_1;
3013  }
3014 
3015  if (neighbor_targets_local[neighbor_el->id] > 0)
3016  continue;
3017 
3018  // Store the level.
3019  neighbor_targets_local[ns.get_neighb_el()->id] = level + 1;
3020  ns.get_neighb_el()->marker = eggShell_marker_volumetric;
3021  }
3022  }
3023  }
3024  }
3025  }
3026  free_with_check(neighbors_target);
3027  }
3028 
3029  void EggShell::handle_vertex_on_target_mesh(Element* e, int vertex, MeshSharedPtr target_mesh, std::vector<int> markers, int* neighbor_targets_local)
3030  {
3031  int eggShell_marker_volumetric = target_mesh->get_element_markers_conversion().get_internal_marker(eggShellMarker).marker;
3032  Node* n;
3033  Node* v = e->vn[vertex];
3034  int max_id = target_mesh->get_max_node_id();
3035  for (int i = 0; i < max_id; i++)
3036  {
3037  n = &target_mesh->nodes[i];
3038  if ((n->p1 == v->id || n->p2 == v->id) && n->used && n->type)
3039  {
3040  bool marker_check_failed[2] = { false, false };
3041  for (unsigned short marker_i = 0; marker_i < markers.size(); marker_i++)
3042  {
3043  if (n->elem[0])
3044  if (n->elem[0]->marker == markers[marker_i])
3045  marker_check_failed[0] = true;
3046  if (n->elem[1])
3047  if (n->elem[1]->marker == markers[marker_i])
3048  marker_check_failed[1] = true;
3049  }
3050  for (unsigned char i = 0; i < 2; i++)
3051  if (n->elem[i] && !marker_check_failed[i])
3052  {
3053  // Store the level.
3054  //neighbor_targets_local[n->elem[i]->id] = 2;
3055  n->elem[i]->marker = eggShell_marker_volumetric;
3056  }
3057  }
3058  }
3059  }
3060 
3061  void EggShell::fix_hanging_nodes(MeshSharedPtr target_mesh)
3062  {
3063  int marker = target_mesh->get_element_markers_conversion().get_internal_marker(eggShellMarker).marker;
3064  for_all_active_elements_fast(target_mesh)
3065  {
3066  if (e->marker != marker)
3067  continue;
3068 
3069  for (int edge = 0; edge < e->nvert; edge++)
3070  {
3071  Node* en = e->en[edge];
3072  if (en->bnd)
3073  continue;
3074 
3075  // eliminate good elements.
3076  if (!(en->elem[0] && en->elem[1]))
3077  {
3078  // eliminate go-down (smaller neighbor)
3079  if (!target_mesh->peek_vertex_node(en->p1, en->p2))
3080  {
3081  bool processed = false;
3082  while (e->parent)
3083  {
3084  Node* parent_edge = target_mesh->peek_edge_node(e->parent->vn[edge]->id, e->parent->vn[(edge + 1) % e->nvert]->id);
3085  // Found edge -> make sure it has some elements (should have)
3086  if (parent_edge)
3087  {
3088  if (parent_edge->elem[0] || parent_edge->elem[1])
3089  {
3090  mark_elements_down_used(marker, e->parent);
3091  processed = true;
3092  break;
3093  }
3094  }
3095  // Not found edge -> have to go up
3096  e = e->parent;
3097  }
3098  // In the worst case, the original (base) element should pass with the correct edge.
3099  assert(processed);
3100  }
3101  }
3102  }
3103  }
3104  }
3105 
3106  void EggShell::mark_elements_down_used(int eggShell_marker_volume, Element* element)
3107  {
3108  if (element->active)
3109  element->marker = eggShell_marker_volume;
3110  else
3111  {
3112  for (int i = 0; i < H2D_MAX_ELEMENT_SONS; i++)
3113  {
3114  if (element->sons[i])
3115  EggShell::mark_elements_down_used(eggShell_marker_volume, element->sons[i]);
3116  }
3117  }
3118  }
3119 
3120  void EggShell::fix_markers(MeshSharedPtr target_mesh, MeshSharedPtr original_mesh)
3121  {
3122  Element* e;
3123  for_all_active_elements(e, target_mesh)
3124  e->marker = original_mesh->get_element(e->id)->marker;
3125  }
3126  }
3127 }
::xsd::cxx::tree::id< char, ncname > id
C++ type corresponding to the ID XML Schema built-in type.
double x
vertex node coordinates
Definition: element.h:63
Node * peek_edge_node(int p1, int p2) const
Returns an edge node with parent id's p1 and p2 if it exists, nullptr otherwise.
Definition: hash.cpp:203
void refine_quad(Element *e, int refinement, Element **sons_out=nullptr)
Definition: mesh.cpp:505
unsigned type
0 = vertex node; 1 = edge node
Definition: element.h:52
Element * element_on_physical_coordinates(double x, double y)
Definition: mesh.cpp:1279
std::map< std::string, int > conversion_table_inverse
Definition: mesh.h:287
void refine_all_elements(int refinement=0, bool mark_as_initial=false)
Definition: mesh.cpp:752
int id
node id number
Definition: element.h:48
Definition: adapt.h:24
Node * get_vertex_node(int p1, int p2)
Definition: hash.cpp:141
unsigned char next_vert(unsigned char i) const
Helper functions to obtain the index of the next or previous vertex/edge.
Definition: element.h:202
unsigned used
array item usage flag
Definition: element.h:56
static bool egg_shell_verbose
Definition: mesh.h:487
void init(int size=H2D_DEFAULT_HASH_SIZE)
Definition: hash.cpp:34
int marker
element marker
Definition: element.h:144
Node * get_edge_node(int p1, int p2)
Definition: hash.cpp:170
int id
element id number
Definition: element.h:112
Node * next_hash
next node in hash synonym list
Definition: element.h:77
bool rescale(double x_ref, double y_ref)
Rescales the mesh.
Definition: mesh.cpp:1106
StringValid get_user_marker(int internal_marker) const
Definition: mesh.cpp:1969
Stores one element of a mesh.
Definition: element.h:107
int get_num_edge_nodes() const
Returns the number of edge nodes.
Definition: mesh.cpp:236
int get_num_base_elements() const
Returns the number of base mesh elements.
Definition: mesh.cpp:171
Represents a finite element mesh. Typical usage: MeshSharedPtr mesh; Hermes::Hermes2D::MeshReaderH2DX...
Definition: mesh.h:61
void copy_converted(MeshSharedPtr mesh)
Copies the active elements of a converted mesh.
Definition: mesh.cpp:1321
bool visited
true if the element has been visited during assembling
Definition: element.h:120
Element * elem[2]
elements sharing the edge node
Definition: element.h:70
void free()
Frees all data associated with the mesh.
Definition: mesh.cpp:1250
void refine_towards_boundary(std::vector< std::string > markers, int depth=1, bool aniso=true, bool mark_as_initial=false)
Definition: mesh.cpp:845
Node * get_node(int id) const
Retrieves a node by its id number.
Definition: hash.cpp:60
Element * get_element_fast(int id) const
For internal use.
Definition: mesh.cpp:311
void initial_single_check()
For internal use.
Definition: mesh.cpp:68
void refine_towards_vertex(int vertex_id, int depth=1, bool mark_as_initial=false)
Definition: mesh.cpp:804
CurvMap * cm
curved mapping, nullptr if not curvilinear
Definition: element.h:188
void unrefine_element_id(int id)
Definition: mesh.cpp:981
void get_bounding_box(double &bottom_left_x, double &bottom_left_y, double &top_right_x, double &top_right_y)
Definition: mesh.cpp:293
void set_ignore_errors(bool value)
Function that sets the variable ignore_errors. See the variable description.
NeighborEdgeInfo get_neighbor_edge() const
Returns the current active neighbor edge according to the current active segment. ...
std::map< int, std::string > conversion_table
Definition: mesh.h:283
Common definitions for Hermes2D.
Stores one node of a mesh.
Definition: element.h:45
static bool same_line(double p_1, double p_2, double q_1, double q_2, double r_1, double r_2)
Checking whether the points p, q, r lie on the same line.
Definition: mesh.cpp:1024
Struct for return type of get_user_marker().
Definition: mesh.h:242
bool is_jacobian_const() const
Definition: refmap.h:95
IntValid get_internal_marker(std::string user_marker) const
Find an internal marker for this user_marker.
Definition: mesh.cpp:1981
bool used
array item usage flag
Definition: element.h:116
int get_num_vertex_nodes() const
Returns the number of vertex nodes.
Definition: mesh.cpp:218
void copy(MeshSharedPtr mesh)
Creates a copy of another mesh.
Definition: mesh.cpp:1126
unsigned char nvert
number of vertices (3 or 4)
Definition: element.h:222
virtual bool isOkay() const
State querying helpers.
Definition: mesh.cpp:43
unsigned get_seq() const
For internal use.
Definition: mesh.cpp:261
void ref_all_nodes()
Internal.
Definition: element.cpp:65
void unref_all_nodes(HashTable *ht)
Internal.
Definition: element.cpp:81
static MeshSharedPtr get_egg_shell(MeshSharedPtr mesh, std::string marker, unsigned int levels)
Definition: mesh.cpp:2774
ReferenceMeshCreator(MeshSharedPtr coarse_mesh, int refinement=0)
Definition: mesh.cpp:56
int insert_marker(std::string user_marker)
Definition: mesh.cpp:1953
int get_max_element_id() const
Returns the maximum node id number plus one.
Definition: mesh.cpp:208
Element * get_neighb_el() const
Returns the current neighbor element according to the current active segment.
#define H2D_MAX_NUMBER_EDGES
A maximum number of edges of an element.
Definition: global.h:31
void free()
Frees all memory used by the instance.
Definition: hash.cpp:115
double * get_jacobian(int order)
Definition: refmap.h:122
Node * peek_vertex_node(int p1, int p2) const
Returns a vertex node with parent id's p1 and p2 if it exists, nullptr otherwise. ...
Definition: hash.cpp:197
Node * en[H2D_MAX_NUMBER_EDGES]
edge node pointers
Definition: element.h:138
unsigned short iro_cache
Increase in integration order, see RefMap::calc_inv_ref_order()
Definition: element.h:199
int get_num_nodes() const
Returns the total number of nodes stored.
Definition: hash.cpp:65
void refine_by_criterion(int(*criterion)(Element *e), int depth=1, bool mark_as_initial=false)
Definition: mesh.cpp:776
void refine_in_area(std::string marker, int depth=1, int refinement=0, bool mark_as_initial=false)
Refines all element sharing the marker passed.
Definition: mesh.cpp:925
static const std::string eggShell0Marker
The mesh returned from get_egg_shell has this marker on the "0" boundary.
Definition: mesh.h:480
void unrefine_all_elements(bool keep_initial_refinements=true)
Definition: mesh.cpp:995
Array< Node > nodes
Array storing all nodes.
Definition: hash.h:77
std::vector< std::pair< unsigned int, int > > refinements
Definition: mesh.h:435
Element * get_element(int id) const
Retrieves an element by its id number.
Definition: mesh.cpp:254
int get_num_elements() const
Returns the total number of elements stored.
Definition: mesh.cpp:162
int p1
parent id numbers
Definition: element.h:75
Struct for return type of get_internal_marker().
Definition: mesh.h:251
unsigned bnd
1 = boundary node; 0 = inner node
Definition: element.h:54
void create(int nv, double2 *verts, int nt, int3 *tris, std::string *tri_markers, int nq, int4 *quads, std::string *quad_markers, int nm, int2 *mark, std::string *boundary_markers)
Creates a mesh from given vertex, triangle, quad, and marker arrays.
Definition: mesh.cpp:104
static const std::string eggShell1Marker
The mesh returned from get_egg_shell has this marker on the "1" boundary.
Definition: mesh.h:478
static double vector_length(double a_1, double a_2)
Computing vector length.
Definition: mesh.cpp:1019
int get_num_used_base_elements() const
Returns the number of used base mesh elements.
Definition: mesh.cpp:181
int * regularize(int n)
Definition: mesh.cpp:2682
::xsd::cxx::tree::string< char, simple_type > string
C++ type corresponding to the string XML Schema built-in type.
static const std::string eggShellMarker
Internal marker for eggshell elements.
Definition: mesh.h:483
Represents the reference mapping.
Definition: refmap.h:40
unsigned ref
the number of elements using the node
Definition: element.h:50
static bool is_convex(double a_1, double a_2, double b_1, double b_2)
Checking whether the angle of vectors 'a' and 'b' is between zero and Pi.
Definition: mesh.cpp:1034
void update_refmap_coeffs(Element *e)
Definition: curved.cpp:758
#define H2D_MAX_ELEMENT_SONS
Macros.
Definition: global.h:30
double2x2 * get_inv_ref_map(int order)
Definition: refmap.h:134
Element * sons[H2D_MAX_ELEMENT_SONS]
son elements (up to four)
Definition: element.h:140
void copy(const HashTable *ht)
Copies another hash table contents.
Definition: hash.cpp:75
This class characterizes a neighborhood of a given edge in terms of adjacent elements and provides me...
int get_num_active_elements() const
Returns the current number of active elements in the mesh.
Definition: mesh.cpp:198
void copy_base(MeshSharedPtr mesh)
Copies the coarsest elements of another mesh.
Definition: mesh.cpp:1193
bool active
0 = active, no sons; 1 = inactive (refined), has sons
Definition: element.h:114
int marker
edge marker
Definition: element.h:68
void refine_in_areas(std::vector< std::string > markers, int depth=1, int refinement=0, bool mark_as_initial=false)
Refines all element sharing the markers passed.
Definition: mesh.cpp:932
void set_seq(unsigned seq)
For internal use.
Definition: mesh.cpp:306
virtual MeshSharedPtr create_ref_mesh()
Definition: mesh.cpp:60
Element * parent
pointer to the parent element for the current son
Definition: element.h:118
static Node * get_base_edge_node(Element *base, int edge)
For internal use.
Definition: mesh_util.cpp:95
void init(int size=H2D_DEFAULT_HASH_SIZE)
Definition: mesh.cpp:1188
int get_max_node_id() const
Returns the maximum node id number plus one.
Definition: hash.cpp:70
virtual void set_active_element(Element *e)
Definition: refmap.cpp:70
Node * vn[H2D_MAX_NUMBER_VERTICES]
vertex node pointers
Definition: element.h:134
static int get_edge_sons(Element *e, int edge, int &son1, int &son2)
For internal use.
Definition: mesh_util.cpp:106
void refine_element_id(int id, int refinement=0)
Definition: mesh.cpp:740