Hermes2D  3.0
space.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 "space_h1.h"
17 #include "space_l2.h"
18 #include "shapeset_hc_all.h"
19 #include "shapeset_hd_all.h"
20 #include "shapeset_h1_all.h"
21 #include "shapeset_l2_all.h"
22 #include "space_hcurl.h"
23 #include "space_hdiv.h"
24 #include "space_h2d_xml.h"
25 #include "api2d.h"
26 
27 namespace Hermes
28 {
29  namespace Hermes2D
30  {
31  template<typename Scalar>
32  SpaceSharedPtr<Scalar>::SpaceSharedPtr(Hermes::Hermes2D::Space<Scalar> * ptr) : std::tr1::shared_ptr<Hermes::Hermes2D::Space<Scalar> >(ptr)
33  {
34  }
35 
36  template<typename Scalar>
37  SpaceSharedPtr<Scalar>::SpaceSharedPtr(const SpaceSharedPtr& other) : std::tr1::shared_ptr<Hermes::Hermes2D::Space<Scalar> >(other)
38  {
39  }
40 
41  template<typename Scalar>
42  void SpaceSharedPtr<Scalar>::operator=(const SpaceSharedPtr& other)
43  {
44  std::tr1::shared_ptr<Hermes::Hermes2D::Space<Scalar> >::operator=(other);
45  }
46 
47  const char* spaceTypeToString(SpaceType spaceType)
48  {
49  switch (spaceType)
50  {
51  case HERMES_H1_SPACE:
52  return "h1";
53  case HERMES_HCURL_SPACE:
54  return "hcurl";
55  case HERMES_HDIV_SPACE:
56  return "hdiv";
57  case HERMES_L2_SPACE:
58  return "l2";
59  case HERMES_L2_MARKERWISE_CONST_SPACE:
60  return "l2-markerwise";
61  case HERMES_INVALID_SPACE:
62  return "invalid";
63  }
64  }
65 
66  SpaceType spaceTypeFromString(const char* spaceTypeString)
67  {
68  if (!strcmp(spaceTypeString, "h1"))
69  return HERMES_H1_SPACE;
70  if (!strcmp(spaceTypeString, "hcurl"))
71  return HERMES_HCURL_SPACE;
72  if (!strcmp(spaceTypeString, "hdiv"))
73  return HERMES_HDIV_SPACE;
74  if (!strcmp(spaceTypeString, "l2"))
75  return HERMES_L2_SPACE;
76  if (!strcmp(spaceTypeString, "l2-markerwise"))
77  return HERMES_L2_MARKERWISE_CONST_SPACE;
78  if (!strcmp(spaceTypeString, "invalid"))
79  return HERMES_INVALID_SPACE;
80  }
81 
82  unsigned g_space_seq = 0;
83 
84  template<typename Scalar>
86  {
87  this->ndata = nullptr;
88  this->edata = nullptr;
89  this->nsize = esize = 0;
90  this->mesh_seq = -1;
91  this->seq = g_space_seq++;
92  this->seq_assigned = -1;
93  this->ndof = 0;
94  this->proj_mat = nullptr;
95  this->chol_p = nullptr;
96  this->vertex_functions_count = this->edge_functions_count = this->bubble_functions_count = 0;
97 
98  if (essential_bcs != nullptr)
99  {
100  for (typename std::vector<EssentialBoundaryCondition<Scalar>*>::const_iterator it = essential_bcs->begin(); it != essential_bcs->end(); it++)
101  for (unsigned int i = 0; i < (*it)->markers.size(); i++)
102  if (mesh->boundary_markers_conversion.conversion_table_inverse.find((*it)->markers.at(i)) == mesh->boundary_markers_conversion.conversion_table_inverse.end() && (*it)->markers.at(i) != HERMES_ANY)
103  throw Hermes::Exceptions::Exception("A boundary condition defined on a non-existent marker %s.", (*it)->markers.at(i).c_str());
104  }
105  own_shapeset = (shapeset == nullptr);
106  }
107 
108  template<typename Scalar>
110  {
111  free_bc_data();
112  if (nsize)
113  {
114  free_with_check(ndata, true);
115  nsize = 0;
116  }
117  if (esize)
118  {
119  free_with_check(edata, true);
120  esize = 0;
121  }
122  this->seq = -1;
123  }
124 
125  template<>
126  Space<double>::Space() : shapeset(nullptr), essential_bcs(nullptr)
127  {
128  this->init();
129  }
130 
131  template<>
132  Space<std::complex<double> >::Space() : shapeset(nullptr), essential_bcs(nullptr)
133  {
134  this->init();
135  }
136 
137  template<typename Scalar>
138  Space<Scalar>::Space(MeshSharedPtr mesh, Shapeset* shapeset, EssentialBCs<Scalar>* essential_bcs)
139  : shapeset(shapeset), essential_bcs(essential_bcs), mesh(mesh)
140  {
141  if (mesh == nullptr)
142  throw Hermes::Exceptions::NullException(0);
143  this->init();
144  }
145 
146  template<typename Scalar>
148  {
149  if (this->mesh)
150  this->mesh->check();
151  else
152  {
153  throw Hermes::Exceptions::Exception("Mesh not present in Space.");
154  return false;
155  }
156 
157  if (ndata == nullptr || edata == nullptr || !nsize || !esize)
158  return false;
159 
160  if (ndof == 0)
161  return false;
162 
163  if (seq < 0)
164  return false;
165 
166  if (edata == nullptr)
167  {
168  throw Hermes::Exceptions::Exception("nullptr edata detected in Space<Scalar>.");
169  return false;
170  }
171 
172  if (!this->is_up_to_date())
173  {
174  throw Hermes::Exceptions::Exception("Space is not up to date.");
175  return false;
176  }
177  else
178  return true;
179  }
180 
181  template<typename Scalar>
183  {
184  free();
185  free_with_check(this->proj_mat, true);
186  free_with_check(this->chol_p);
187 
188  if (this->own_shapeset)
189  delete this->shapeset;
190  }
191 
192  template<typename Scalar>
193  Node* Space<Scalar>::get_mid_edge_vertex_node(Element* e, unsigned char i, unsigned char j)
194  {
195  unsigned char prev = e->prev_vert(i);
196  if (e->is_triangle())
197  return e->sons[3]->vn[e->prev_vert(i)];
198  else if (e->sons[2] == nullptr)
199  return i == 1 ? e->sons[0]->vn[2] : i == 3 ? e->sons[0]->vn[3] : nullptr;
200  else if (e->sons[0] == nullptr)
201  return i == 0 ? e->sons[2]->vn[1] : i == 2 ? e->sons[2]->vn[2] : nullptr;
202  else return e->sons[i]->vn[j];
203  }
204 
205  template<typename Scalar>
207  {
208  if ((nsize < mesh->get_max_node_id()) || (ndata == nullptr))
209  {
210  int oldsize = nsize;
211  if (!nsize)
212  nsize = 1024;
213  while (nsize < mesh->get_max_node_id())
214  nsize = nsize * 3 / 2;
215  ndata = realloc_with_check<Space<Scalar>, NodeData>(ndata, nsize, this);
216  for (int i = oldsize; i < nsize; i++)
217  {
218  ndata[i].edge_bc_proj = nullptr;
219  ndata[i].baselist = nullptr;
220  ndata[i].base = nullptr;
221  }
222  }
223 
224  if ((esize < mesh->get_max_element_id()) || (edata == nullptr))
225  {
226  int oldsize = esize;
227  if (!esize)
228  esize = 1024;
229  while (esize < mesh->get_max_element_id())
230  esize = esize * 3 / 2;
231  edata = realloc_with_check<Space<Scalar>, ElementData>(edata, nsize, this);
232  for (int i = oldsize; i < esize; i++)
233  {
234  edata[i].order = -1;
235  edata[i].bdof = -1;
236  edata[i].n = -1;
237  edata[i].changed_in_last_adaptation = true;
238  }
239  }
240  }
241 
242  template<typename Scalar>
243  void Space<Scalar>::copy(SpaceSharedPtr<Scalar> space, MeshSharedPtr new_mesh)
244  {
245  this->free();
246  this->vertex_functions_count = this->edge_functions_count = this->bubble_functions_count = 0;
247 
248  this->essential_bcs = space->essential_bcs;
249 
250  if (new_mesh->get_seq() != space->get_mesh()->get_seq())
251  {
252  new_mesh->copy(space->get_mesh());
253  this->mesh = new_mesh;
254  }
255  else
256  this->mesh = space->get_mesh();
257 
258  this->resize_tables();
259 
260  Element* e;
261  for_all_active_elements(e, this->mesh)
262  {
263  this->set_element_order_internal(e->id, space->get_element_order(e->id));
264  }
265 
266  this->seq = g_space_seq++;
267 
268  for_all_active_elements(e, this->mesh)
269  {
270  if (space->edata[e->id].changed_in_last_adaptation)
271  this->edata[e->id].changed_in_last_adaptation = true;
272  else
273  this->edata[e->id].changed_in_last_adaptation = false;
274  }
275 
276  this->assign_dofs();
277  }
278 
279  template<typename Scalar>
281  {
282  return this->shapeset;
283  }
284 
285  template<typename Scalar>
287  {
288  check();
289  return ndof;
290  }
291 
292  template<typename Scalar>
294  {
295  check();
296  return next_dof - 1;
297  }
298 
299  template<typename Scalar>
300  MeshSharedPtr Space<Scalar>::get_mesh() const
301  {
302  return mesh;
303  }
304 
305  template<typename Scalar>
307  {
308  return (seq_assigned == this->seq) && (mesh_seq == mesh->get_seq());
309  }
310 
311  template<typename Scalar>
313  {
314  check();
315  return essential_bcs;
316  }
317 
318  template<typename Scalar>
319  void Space<Scalar>::set_element_order(int id, int order, int order_v)
320  {
321  set_element_order_internal(id, order, order_v);
322  }
323 
324  template<typename Scalar>
325  void Space<Scalar>::set_element_order_internal(int id, int order, int order_v)
326  {
327 #ifdef _DEBUG
328  if (id < 0 || id >= mesh->get_max_element_id())
329  throw Hermes::Exceptions::Exception("Space<Scalar>::set_element_order_internal: Invalid element id.");
330 #endif
331 
332  resize_tables();
333 
334  if (mesh->get_element(id)->is_quad() && H2D_GET_V_ORDER(order) == 0)
335  if (order_v != -1)
336  order = H2D_MAKE_QUAD_ORDER(order, order_v);
337  else
338  order = H2D_MAKE_QUAD_ORDER(order, order);
339 
340  edata[id].order = order;
341  seq = g_space_seq++;
342  }
343 
344  template<typename Scalar>
346  {
347  int n = spaces.size();
348  for (int i = 0; i < n; i++)
349  {
350  if (spaces[i]->get_essential_bcs() != nullptr)
351  spaces[i]->get_essential_bcs()->set_current_time(time);
352  spaces[i]->update_essential_bc_values();
353  }
354  }
355 
356  template<typename Scalar>
357  void Space<Scalar>::update_essential_bc_values(SpaceSharedPtr<Scalar> space, double time)
358  {
359  space->get_essential_bcs()->set_current_time(time);
360  space->update_essential_bc_values();
361  }
362 
363  template<typename Scalar>
365  {
366  int ndof = 0;
367  for (unsigned char i = 0; i < spaces.size(); i++)
368  ndof += spaces[i]->get_num_dofs();
369  return ndof;
370  }
371 
372  template<typename Scalar>
374  {
375  return space->get_num_dofs();
376  }
377 
378  template<typename Scalar>
380  {
381  int n = spaces.size();
382 
383  int ndof = 0;
384  for (int i = 0; i < n; i++) {
385  ndof += spaces[i]->assign_dofs(ndof);
386  }
387 
388  return ndof;
389  }
390 
391  template<typename Scalar>
393  {
394  if (marker == HERMES_ANY)
395  set_uniform_order_internal(order, -1234);
396  else
397  set_uniform_order_internal(order, mesh->element_markers_conversion.get_internal_marker(marker).marker);
398  }
399 
400  template<typename Scalar>
401  void Space<Scalar>::set_uniform_order_internal(int order, int marker)
402  {
403  resize_tables();
404  int quad_order = H2D_MAKE_QUAD_ORDER(order, order);
405 
406  Element* e;
407  for_all_active_elements(e, mesh)
408  {
409  if (marker == HERMES_ANY_INT || e->marker == marker)
410  {
411  ElementData* ed = &edata[e->id];
412  if (e->is_triangle())
413  ed->order = order;
414  else
415  ed->order = quad_order;
416  }
417  }
418  seq = g_space_seq++;
419  }
420 
421  template<typename Scalar>
422  void Space<Scalar>::adjust_element_order(int order_change, int min_order)
423  {
424  Element* e;
425  for_all_active_elements(e, this->get_mesh())
426  {
427  if (e->is_triangle())
428  set_element_order_internal(e->id, std::max<int>(min_order, get_element_order(e->id) + order_change));
429  else
430  {
431  int h_order, v_order;
432 
433  if (H2D_GET_H_ORDER(get_element_order(e->id)) + order_change < min_order)
434  h_order = min_order;
435  else
436  h_order = H2D_GET_H_ORDER(get_element_order(e->id)) + order_change;
437 
438  if (H2D_GET_V_ORDER(get_element_order(e->id)) + order_change < min_order)
439  v_order = min_order;
440  else
441  v_order = H2D_GET_V_ORDER(get_element_order(e->id)) + order_change;
442 
443  set_element_order_internal(e->id, H2D_MAKE_QUAD_ORDER(h_order, v_order));
444  }
445  }
446  }
447 
448  template<typename Scalar>
449  void Space<Scalar>::adjust_element_order(int horizontal_order_change, int vertical_order_change, unsigned int horizontal_min_order, unsigned int vertical_min_order)
450  {
451  Element* e;
452  for_all_active_elements(e, this->get_mesh())
453  {
454  if (e->is_triangle())
455  {
456  this->warn("Using quad version of Space<Scalar>::adjust_element_order(), only horizontal orders will be used.");
457  set_element_order_internal(e->id, std::max<int>(horizontal_min_order, get_element_order(e->id) + horizontal_order_change));
458  }
459  else
460  if (get_element_order(e->id) == -1)
461  set_element_order_internal(e->id, H2D_MAKE_QUAD_ORDER(horizontal_min_order, vertical_min_order));
462  else
463  set_element_order_internal(e->id, H2D_MAKE_QUAD_ORDER(std::max<int>(H2D_GET_H_ORDER(get_element_order(e->id)) + horizontal_order_change, horizontal_min_order), std::max<int>(H2D_GET_V_ORDER(get_element_order(e->id)) + vertical_order_change, vertical_min_order)));
464  }
465  }
466 
467  template<typename Scalar>
468  void Space<Scalar>::unrefine_all_mesh_elements_internal(bool keep_initial_refinements, bool only_unrefine_space_data)
469  {
470  // find inactive elements with active sons
471  std::vector<int> list;
472  Element* e;
473  for_all_inactive_elements(e, this->mesh)
474  {
475  bool found = true;
476  for (unsigned int i = 0; i < 4; i++)
477  if (e->sons[i] != nullptr &&
478  (!e->sons[i]->active || (keep_initial_refinements && e->sons[i]->id < this->mesh->ninitial))
479  )
480  {
481  found = false; break;
482  }
483 
484  if (found) list.push_back(e->id);
485  }
486 
487  // unrefine the found elements
488  for (unsigned int i = 0; i < list.size(); i++)
489  {
490  unsigned int order = 0, h_order = 0, v_order = 0;
491  unsigned int num_sons = 0;
492  if (this->mesh->get_element_fast(list[i])->bsplit())
493  {
494  num_sons = 4;
495  for (int sons_i = 0; sons_i < 4; sons_i++)
496  {
497  if (this->mesh->get_element_fast(list[i])->sons[sons_i]->active)
498  {
499  if (this->mesh->get_element_fast(list[i])->sons[sons_i]->is_triangle())
500  order += this->get_element_order(this->mesh->get_element_fast(list[i])->sons[sons_i]->id);
501  else
502  {
503  h_order += H2D_GET_H_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[sons_i]->id));
504  v_order += H2D_GET_V_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[sons_i]->id));
505  }
506  }
507  }
508  }
509  else
510  {
511  if (this->mesh->get_element_fast(list[i])->hsplit())
512  {
513  num_sons = 2;
514  if (this->mesh->get_element_fast(list[i])->sons[0]->active)
515  {
516  if (this->mesh->get_element_fast(list[i])->sons[0]->is_triangle())
517  order += this->get_element_order(this->mesh->get_element_fast(list[i])->sons[0]->id);
518  else
519  {
520  h_order += H2D_GET_H_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[0]->id));
521  v_order += H2D_GET_V_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[0]->id));
522  }
523  }
524  if (this->mesh->get_element_fast(list[i])->sons[1]->active)
525  {
526  if (this->mesh->get_element_fast(list[i])->sons[1]->is_triangle())
527  order += this->get_element_order(this->mesh->get_element_fast(list[i])->sons[1]->id);
528  else
529  {
530  h_order += H2D_GET_H_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[1]->id));
531  v_order += H2D_GET_V_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[1]->id));
532  }
533  }
534  }
535  else
536  {
537  num_sons = 2;
538  if (this->mesh->get_element_fast(list[i])->sons[2]->active)
539  {
540  if (this->mesh->get_element_fast(list[i])->sons[2]->is_triangle())
541  order += this->get_element_order(this->mesh->get_element_fast(list[i])->sons[2]->id);
542  else
543  {
544  h_order += H2D_GET_H_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[2]->id));
545  v_order += H2D_GET_V_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[2]->id));
546  }
547  }
548  if (this->mesh->get_element_fast(list[i])->sons[3]->active)
549  {
550  if (this->mesh->get_element_fast(list[i])->sons[3]->is_triangle())
551  order += this->get_element_order(this->mesh->get_element_fast(list[i])->sons[3]->id);
552  else
553  {
554  h_order += H2D_GET_H_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[3]->id));
555  v_order += H2D_GET_V_ORDER(this->get_element_order(this->mesh->get_element_fast(list[i])->sons[3]->id));
556  }
557  }
558  }
559  }
560  order = (unsigned int)(order / num_sons);
561  h_order = (unsigned int)(h_order / num_sons);
562  v_order = (unsigned int)(v_order / num_sons);
563 
564  if (this->mesh->get_element_fast(list[i])->is_triangle())
565  edata[list[i]].order = order;
566  else
567  edata[list[i]].order = H2D_MAKE_QUAD_ORDER(h_order, v_order);
568 
569  if (!only_unrefine_space_data)
570  this->mesh->unrefine_element_id(list[i]);
571  }
572 
573  // Recalculate all integrals, do not use previous adaptivity step.
574  for_all_active_elements(e, this->mesh)
575  this->edata[e->id].changed_in_last_adaptation = true;
576  }
577 
578  template<typename Scalar>
579  void Space<Scalar>::unrefine_all_mesh_elements(bool keep_initial_refinements)
580  {
581  this->check();
582  this->unrefine_all_mesh_elements_internal(keep_initial_refinements, false);
583  }
584 
585  template<typename Scalar>
586  void Space<Scalar>::unrefine_all_mesh_elements(std::vector<SpaceSharedPtr<Scalar> > spaces, bool keep_initial_refinements)
587  {
588  for (unsigned char i = 0; i < spaces.size() - 1; i++)
589  spaces[i]->unrefine_all_mesh_elements_internal(keep_initial_refinements, true);
590 
591  spaces[spaces.size() - 1]->unrefine_all_mesh_elements_internal(keep_initial_refinements, false);
592  }
593 
594  template<typename Scalar>
595  Space<Scalar>::ReferenceSpaceCreator::ReferenceSpaceCreator(unsigned int order_increase) : order_increase(order_increase)
596  {
597  }
598 
599  template<typename Scalar>
600  Space<Scalar>::ReferenceSpaceCreator::ReferenceSpaceCreator(SpaceSharedPtr<Scalar> coarse_space, MeshSharedPtr ref_mesh, unsigned int order_increase) : coarse_space(coarse_space), ref_mesh(ref_mesh), order_increase(order_increase)
601  {
602  }
603 
604  template<typename Scalar>
606  {
607  Element* e;
608  for_all_active_elements(e, coarse_space->get_mesh())
609  {
610  // This is the element id on the COARSE mesh. One can use it in the logic of increasing polynomial order (selectively).
611  int coarse_element_id = e->id;
612 
613  // Get the current order (may be triangular or quadrilateral - in the latter case, it is both horizontal and vertical order encoded in one number).
614  int current_order = coarse_space->get_element_order(coarse_element_id);
615  // Sanity check.
616  if (current_order < 0)
617  throw Hermes::Exceptions::Exception("Source space has an uninitialized order (element id = %d)", coarse_element_id);
618 
619  // new_ order calculation.
620  int new_order;
621  if (e->is_triangle())
622  {
623  // The triangular order is just the current order.
624  int current_order_triangular = current_order;
625  // This is the default setup, we ALWAYS increase by attribute of this functor class: 'order_increase'.
626  // This is OVERRIDABLE. Plus when overriding, one does not have to care about min / max possible values (due to shapeset, Space requirements).
627  // These are guarded internally.
628  new_order = current_order_triangular + this->order_increase;
629  }
630  else
631  {
632  // We have to get the proper parts of the encoded order.
633  // - horizontal.
634  int current_order_quadrilateral_horizontal = H2D_GET_H_ORDER(current_order);
635  // - vertical.
636  int current_order_quadrilateral_vertical = H2D_GET_V_ORDER(current_order);
637 
638  // And now we have to create the new_ encoded order.
639  int new_order_quadrilateral_horizontal = current_order_quadrilateral_horizontal + this->order_increase;
640  int new_order_quadrilateral_vertical = current_order_quadrilateral_vertical + this->order_increase;
641  new_order = H2D_MAKE_QUAD_ORDER(new_order_quadrilateral_horizontal, new_order_quadrilateral_vertical);
642  }
643 
644  // And now call this method that does the magic for us (sets the new_order to .
645  ref_space->update_orders_recurrent(ref_space->mesh->get_element(coarse_element_id), new_order);
646  }
647  }
648 
649  template<typename Scalar>
651  {
652  this->coarse_space = coarse_space;
653  this->ref_mesh = ref_mesh;
654  return this->create_ref_space(assign_dofs);
655  }
656 
657  template<typename Scalar>
659  {
660  // Initialization.
661  // Important - for L2MarkerWiseConstSpace we do not create reference spaces - it would be a waste, and shared pointers will take care of the deallocation.
662  if (dynamic_cast<L2MarkerWiseConstSpace<Scalar>*>(this->coarse_space.get()) != nullptr)
663  return this->coarse_space;
664 
665  SpaceSharedPtr<Scalar> ref_space;
666  if (dynamic_cast<L2Space<Scalar>*>(this->coarse_space.get()) != nullptr)
667  ref_space = this->init_construction_l2();
668  if (dynamic_cast<H1Space<Scalar>*>(this->coarse_space.get()) != nullptr)
669  ref_space = this->init_construction_h1();
670  if (dynamic_cast<HcurlSpace<Scalar>*>(this->coarse_space.get()) != nullptr)
671  ref_space = this->init_construction_hcurl();
672  if (dynamic_cast<HdivSpace<Scalar>*>(this->coarse_space.get()) != nullptr)
673  ref_space = this->init_construction_hdiv();
674 
675  if (ref_space == nullptr)
676  throw Exceptions::Exception("Something went wrong in ReferenceSpaceCreator::create_ref_space().");
677 
678  // Call to the OVERRIDABLE handling method.
679  this->handle_orders(ref_space);
680 
681  // Finish - MUST BE CALLED BEFORE RETURN.
682  this->finish_construction(ref_space);
683 
684  // Assign dofs?
685  if (assign_dofs)
686  ref_space->assign_dofs();
687 
688  // Return.
689  return ref_space;
690  }
691 
692  template<typename Scalar>
694  {
695  if (this->coarse_space->own_shapeset)
696  return SpaceSharedPtr<Scalar>(new L2Space<Scalar>(this->ref_mesh, 0));
697  else
698  return SpaceSharedPtr<Scalar>(new L2Space<Scalar>(this->ref_mesh, 0, this->coarse_space->get_shapeset()));
699  }
700 
701  template<typename Scalar>
703  {
704  if (this->coarse_space->own_shapeset)
705  return SpaceSharedPtr<Scalar>(new H1Space<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1));
706  else
707  return SpaceSharedPtr<Scalar>(new H1Space<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1, this->coarse_space->get_shapeset()));
708  }
709 
710  template<typename Scalar>
711  SpaceSharedPtr<Scalar> Space<Scalar>::ReferenceSpaceCreator::init_construction_hcurl()
712  {
713  if (this->coarse_space->own_shapeset)
714  return SpaceSharedPtr<Scalar>(new HcurlSpace<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1));
715  else
716  return SpaceSharedPtr<Scalar>(new HcurlSpace<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1, this->coarse_space->get_shapeset()));
717  }
718 
719  template<typename Scalar>
720  SpaceSharedPtr<Scalar> Space<Scalar>::ReferenceSpaceCreator::init_construction_hdiv()
721  {
722  if (this->coarse_space->own_shapeset)
723  return SpaceSharedPtr<Scalar>(new HdivSpace<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1));
724  else
725  return SpaceSharedPtr<Scalar>(new HdivSpace<Scalar>(this->ref_mesh, this->coarse_space->get_essential_bcs(), 1, this->coarse_space->get_shapeset()));
726  }
727 
728  template<typename Scalar>
729  void Space<Scalar>::ReferenceSpaceCreator::finish_construction(SpaceSharedPtr<Scalar> ref_space)
730  {
731  ref_space->seq = g_space_seq++;
732 
733  Element *e;
734  for_all_active_elements(e, coarse_space->get_mesh())
735  {
736  bool to_set = this->coarse_space->edata[e->id].changed_in_last_adaptation;
737  {
738  if (ref_space->mesh->get_element(e->id)->active)
739  ref_space->edata[e->id].changed_in_last_adaptation = to_set;
740  else
741  for (unsigned int i = 0; i < 4; i++)
742  if (ref_space->mesh->get_element(e->id)->sons[i] != nullptr)
743  if (ref_space->mesh->get_element(e->id)->sons[i]->active)
744  ref_space->edata[ref_space->mesh->get_element(e->id)->sons[i]->id].changed_in_last_adaptation = to_set;
745  }
746  }
747  }
748 
749  template<typename Scalar>
750  void Space<Scalar>::update_orders_recurrent(Element* e, int order)
751  {
752  // Adjust wrt. max and min possible orders.
753  int mo = shapeset->get_max_order();
754  // L2 and Hcurl may use zero orders.
755  int lower_limit = (get_type() == HERMES_L2_SPACE || get_type() == HERMES_L2_MARKERWISE_CONST_SPACE || get_type() == HERMES_HCURL_SPACE) ? 0 : 1;
756  int ho = std::max(lower_limit, std::min(H2D_GET_H_ORDER(order), mo));
757  int vo = std::max(lower_limit, std::min(H2D_GET_V_ORDER(order), mo));
758  order = e->is_triangle() ? ho : H2D_MAKE_QUAD_ORDER(ho, vo);
759 
760  if (e->active)
761  edata[e->id].order = order;
762  else
763  for (int i = 0; i < 4; i++)
764  if (e->sons[i] != nullptr)
765  update_orders_recurrent(e->sons[i], order);
766  }
767 
768  template<typename Scalar>
769  int Space<Scalar>::get_edge_order(Element* e, int edge) const
770  {
771  Node* en = e->en[edge];
772  if (en->id >= nsize || edge >= e->get_nvert())
773  return 0;
774 
775  if (ndata[en->id].n == -1)
776  // constrained node
777  return get_edge_order_internal(ndata[en->id].base);
778  else
779  return get_edge_order_internal(en);
780  }
781 
782  template<typename Scalar>
784  {
785  assert(en->type == HERMES_TYPE_EDGE);
786  Element** e = en->elem;
787  int o1 = 1000, o2 = 1000;
788  assert(e[0] != nullptr || e[1] != nullptr);
789 
790  if (e[0] != nullptr)
791  {
792  if (e[0]->is_triangle() || en == e[0]->en[0] || en == e[0]->en[2])
793  o1 = H2D_GET_H_ORDER(edata[e[0]->id].order);
794  else
795  o1 = H2D_GET_V_ORDER(edata[e[0]->id].order);
796  }
797 
798  if (e[1] != nullptr)
799  {
800  if (e[1]->is_triangle() || en == e[1]->en[0] || en == e[1]->en[2])
801  o2 = H2D_GET_H_ORDER(edata[e[1]->id].order);
802  else
803  o2 = H2D_GET_V_ORDER(edata[e[1]->id].order);
804  }
805 
806  if (o1 == 0) return o2 == 1000 ? 0 : o2;
807  if (o2 == 0) return o1 == 1000 ? 0 : o1;
808  return std::min(o1, o2);
809  }
810 
811  template<typename Scalar>
812  void Space<Scalar>::set_mesh(MeshSharedPtr mesh)
813  {
814  if (this->mesh == mesh)
815  return;
816  free();
817  this->mesh = mesh;
818  this->mesh_seq = mesh->get_seq();
819  seq = g_space_seq++;
820  }
821 
822  template<typename Scalar>
824  {
825  this->mesh_seq = seq;
826  this->mesh->set_seq(seq);
827  }
828 
829  template<typename Scalar>
831  {
832  }
833 
834  template<typename Scalar>
836  {
837  }
838 
839  template<typename Scalar>
841  {
842  return seq;
843  }
844 
845  template<typename Scalar>
846  void Space<Scalar>::distribute_orders(MeshSharedPtr mesh, int* parents)
847  {
848  int num = mesh->get_max_element_id();
849  int* orders = malloc_with_check<Space<Scalar>, int>(num + 1, this);
850  Element* e;
851  for_all_active_elements(e, mesh)
852  {
853  int p = get_element_order(parents[e->id]);
854  if (e->is_triangle() && (H2D_GET_V_ORDER(p) != 0))
855  p = std::max(H2D_GET_H_ORDER(p), H2D_GET_V_ORDER(p));
856  orders[e->id] = p;
857  }
858  for_all_active_elements(e, mesh)
859  set_element_order_internal(e->id, orders[e->id]);
860  free_with_check(orders);
861  }
862 
863  template<typename Scalar>
865  {
866  if (ndata == nullptr || edata == nullptr || !nsize || !esize)
867  return false;
868  if (seq < 0)
869  return false;
870  if (this->mesh == nullptr)
871  return false;
872 
873  this->mesh->check();
874 
875  if (edata == nullptr)
876  {
877  throw Hermes::Exceptions::Exception("nullptr edata detected in Space<Scalar>::assign_dofs().");
878  return false;
879  }
880 
881  if (first_dof < 0)
882  throw Hermes::Exceptions::ValueException("first_dof", first_dof, 0);
883 
884  resize_tables();
885 
886  this->first_dof = next_dof = first_dof;
887 
889  assign_vertex_dofs();
890  assign_edge_dofs();
891  assign_bubble_dofs();
892 
893  free_bc_data();
896  post_assign();
897 
898  this->mesh_seq = mesh->get_seq();
899  seq_assigned = this->seq;
900  this->ndof = next_dof - first_dof;
901 
902  this->check();
903  return this->ndof;
904  }
905 
906  template<typename Scalar>
908  {
909  // First assume that all vertex nodes are part of a natural BC. the member NodeData::n
910  // is misused for this purpose, since it stores nothing at this point. Also assume
911  // that all DOFs are unassigned.
912  int i, j;
913  for (i = 0; i < mesh->get_max_node_id(); i++)
914  {
915  // Natural boundary condition. The point is that it is not (0 == Dirichlet).
916  ndata[i].n = 1;
917  ndata[i].dof = H2D_UNASSIGNED_DOF;
918  }
919 
920  // next go through all boundary edge nodes constituting an essential BC and mark their
921  // neighboring vertex nodes also as essential
922  Element* e;
923  for_all_active_elements(e, mesh)
924  {
925  for (unsigned char i = 0; i < e->get_nvert(); i++)
926  {
927  if (e->en[i]->bnd)
928  if (essential_bcs != nullptr)
929  if (essential_bcs->get_boundary_condition(mesh->boundary_markers_conversion.get_user_marker(e->en[i]->marker).marker) != nullptr)
930  {
931  j = e->next_vert(i);
932  ndata[e->vn[i]->id].n = 0;
933  ndata[e->vn[j]->id].n = 0;
934  }
935  }
936  }
937  }
938 
939  template<typename Scalar>
941  {
942  return this->vertex_functions_count;
943  }
944 
945  template<typename Scalar>
947  {
948  return this->edge_functions_count;
949  }
950 
951  template<typename Scalar>
953  {
954  return this->bubble_functions_count;
955  }
956 
957  template<typename Scalar>
959  {
960  this->check();
961  // some checks
962  if (e->id >= esize || edata[e->id].order < 0)
963  throw Hermes::Exceptions::Exception("Uninitialized element order in get_element_assembly_list(id = #%d).", e->id);
964  if (!is_up_to_date())
965  throw Hermes::Exceptions::Exception("The space in get_element_assembly_list() is out of date. You need to update it with assign_dofs()"
966  " any time the mesh changes.");
967 
968  // add vertex, edge and bubble functions to the assembly list
969  al->cnt = 0;
970  for (unsigned char i = 0; i < e->get_nvert(); i++)
971  get_vertex_assembly_list(e, i, al);
972  for (unsigned char i = 0; i < e->get_nvert(); i++)
973  get_boundary_assembly_list_internal(e, i, al);
974  get_bubble_assembly_list(e, al);
975  }
976 
977  template<typename Scalar>
979  {
980  this->check();
981  al->cnt = 0;
982  get_vertex_assembly_list(e, surf_num, al);
983  get_vertex_assembly_list(e, e->next_vert(surf_num), al);
984  get_boundary_assembly_list_internal(e, surf_num, al);
985  }
986 
987  template<typename Scalar>
989  {
990  this->check();
991  ElementData* ed = &edata[e->id];
992 
993  if (!ed->n) return;
994 
995  short* indices = shapeset->get_bubble_indices(ed->order, e->get_mode());
996  for (int i = 0, dof = ed->bdof; i < ed->n; i++, dof++, indices++)
997  al->add_triplet(*indices, dof, 1.0);
998  }
999 
1000  template<typename Scalar>
1002  {
1003  this->essential_bcs = essential_bcs;
1004  }
1005 
1006  template<typename Scalar>
1007  void Space<Scalar>::precalculate_projection_matrix(int nv, double**& mat, double*& p)
1008  {
1009  unsigned char n = shapeset->get_max_order() + 1 - nv;
1010  mat = new_matrix<double>(n, n);
1011  int component = (get_type() == HERMES_HDIV_SPACE) ? 1 : 0;
1012 
1013  Quad1DStd quad1d;
1014  for (unsigned char i = 0; i < n; i++)
1015  {
1016  for (unsigned char j = i; j < n; j++)
1017  {
1018  int o = i + j + 4;
1019  double2* pt = quad1d.get_points(o);
1020  int ii = shapeset->get_edge_index(0, 0, i + nv, HERMES_MODE_QUAD);
1021  int ij = shapeset->get_edge_index(0, 0, j + nv, HERMES_MODE_QUAD);
1022  double val = 0.0;
1023  for (int k = 0; k < quad1d.get_num_points(o); k++)
1024  {
1025  double val_ii = shapeset->get_fn_value(ii, pt[k][0], -1.0, component, HERMES_MODE_QUAD);
1026  double val_ij = shapeset->get_fn_value(ij, pt[k][0], -1.0, component, HERMES_MODE_QUAD);
1027  val += pt[k][1] * val_ii * val_ij;
1028  }
1029  mat[i][j] = val;
1030  }
1031  }
1032 
1033  p = malloc_with_check<Space<Scalar>, double>(n, this);
1034  choldc(mat, n, p);
1035  }
1036 
1037  template<typename Scalar>
1038  void Space<Scalar>::update_edge_bc(Element* e, SurfPos* surf_pos)
1039  {
1040  if (!e->used)
1041  return;
1042 
1043  assert(e->active);
1044 
1045  Node* en = e->en[surf_pos->surf_num];
1046  NodeData* nd = &ndata[en->id];
1047  nd->edge_bc_proj = nullptr;
1048 
1049  if (nd->dof != H2D_UNASSIGNED_DOF && en->bnd)
1050  if (essential_bcs != nullptr)
1051  {
1052  EssentialBoundaryCondition<Scalar> *bc = this->essential_bcs->get_boundary_condition(this->mesh->boundary_markers_conversion.get_user_marker(en->marker).marker);
1053  if (bc != nullptr)
1054  {
1055  int order = get_edge_order_internal(en);
1056  surf_pos->marker = en->marker;
1057  nd->edge_bc_proj = get_bc_projection(surf_pos, order, bc);
1058  bc_data_projections.push_back(nd->edge_bc_proj);
1059 
1060  int i = surf_pos->surf_num, j = e->next_vert(i);
1061  ndata[e->vn[i]->id].vertex_bc_coef = nd->edge_bc_proj + 0;
1062  ndata[e->vn[j]->id].vertex_bc_coef = nd->edge_bc_proj + 1;
1063  }
1064  }
1065  }
1066 
1067  template<typename Scalar>
1069  {
1070  Element* e;
1071  for_all_active_elements(e, mesh)
1072  {
1073  for (unsigned char i = 0; i < e->get_nvert(); i++)
1074  {
1075  int j = e->next_vert(i);
1076  if (e->vn[i]->bnd && e->vn[j]->bnd)
1077  {
1078  SurfPos surf_pos = { 0, i, e, e->vn[i]->id, e->vn[j]->id, 0.0, 0.0, 1.0 };
1079  update_edge_bc(e, &surf_pos);
1080  }
1081  }
1082  }
1083  }
1084 
1085  template<typename Scalar>
1087  {
1088  for (unsigned int i = 0; i < bc_data_projections.size(); i++)
1089  free_with_check(bc_data_projections[i]);
1090  for (unsigned int i = 0; i < bc_data_base_components.size(); i++)
1091  free_with_check(bc_data_base_components[i]);
1092  bc_data_projections.clear();
1093  bc_data_base_components.clear();
1094  }
1095 
1096  template<typename Scalar>
1097  void Space<Scalar>::save(const char *filename) const
1098  {
1099  this->check();
1100  XMLSpace::space xmlspace;
1101 
1102  xmlspace.spaceType().set(spaceTypeToString(this->get_type()));
1103 
1104  // Utility pointer.
1105  Element *e;
1106  for_all_used_elements(e, this->get_mesh())
1107  xmlspace.element_data().push_back(XMLSpace::space::element_data_type(e->id, this->edata[e->id].order, this->edata[e->id].bdof, this->edata[e->id].n, this->edata[e->id].changed_in_last_adaptation));
1108 
1109  ::xml_schema::namespace_infomap namespace_info_map;
1110  std::ofstream out(filename);
1111  ::xml_schema::flags parsing_flags = ::xml_schema::flags::dont_pretty_print;
1112  XMLSpace::space_(out, xmlspace, namespace_info_map, "UTF-8", parsing_flags);
1113  out.close();
1114  }
1115 
1116 #ifdef WITH_BSON
1117  template<typename Scalar>
1118  void Space<Scalar>::save_bson(const char *filename) const
1119  {
1120  // Check.
1121  this->check();
1122 
1123  // Init bson
1124  bson bw;
1125  bson_init(&bw);
1126 
1127  // Space type.
1128  bson_append_string(&bw, "type", spaceTypeToString(this->get_type()));
1129 
1130  // Count.
1131  bson_append_int(&bw, "element_data_count", this->mesh->get_max_element_id());
1132 
1133  // Coefficients.
1134  bson_append_start_array(&bw, "orders");
1135  for (int _id = 0, _max = this->get_mesh()->get_max_element_id(); _id < _max; _id++)
1136  bson_append_int(&bw, "c", this->edata[_id].order);
1137  bson_append_finish_array(&bw);
1138 
1139  bson_append_start_array(&bw, "bdofs");
1140  for (int _id = 0, _max = this->get_mesh()->get_max_element_id(); _id < _max; _id++)
1141  bson_append_int(&bw, "c", this->edata[_id].bdof);
1142  bson_append_finish_array(&bw);
1143 
1144  bson_append_start_array(&bw, "ns");
1145  for (int _id = 0, _max = this->get_mesh()->get_max_element_id(); _id < _max; _id++)
1146  bson_append_int(&bw, "c", this->edata[_id].n);
1147  bson_append_finish_array(&bw);
1148 
1149  bson_append_start_array(&bw, "changed");
1150  for (int _id = 0, _max = this->get_mesh()->get_max_element_id(); _id < _max; _id++)
1151  bson_append_bool(&bw, "c", this->edata[_id].changed_in_last_adaptation);
1152  bson_append_finish_array(&bw);
1153 
1154  // Done.
1155  bson_finish(&bw);
1156 
1157  // Write to disk.
1158  FILE *fpw;
1159  fpw = fopen(filename, "wb");
1160  const char *dataw = (const char *)bson_data(&bw);
1161  fwrite(dataw, bson_size(&bw), 1, fpw);
1162  fclose(fpw);
1163 
1164  bson_destroy(&bw);
1165  }
1166 #endif
1167 
1168  template<typename Scalar>
1169  SpaceSharedPtr<Scalar> Space<Scalar>::init_empty_space(SpaceType spaceType, MeshSharedPtr mesh, Shapeset* shapeset)
1170  {
1171  SpaceSharedPtr<Scalar> space(nullptr);
1172 
1173  if (spaceType == HERMES_H1_SPACE)
1174  {
1175  space = new H1Space<Scalar>();
1176  space->mesh = mesh;
1177 
1178  if (shapeset == nullptr)
1179  {
1180  space->shapeset = new H1Shapeset;
1181  space->own_shapeset = true;
1182  }
1183  else
1184  {
1185  if (shapeset->get_space_type() != HERMES_H1_SPACE)
1186  throw Hermes::Exceptions::SpaceLoadFailureException("Wrong shapeset / Wrong spaceType in Space loading subroutine.");
1187  else
1188  space->shapeset = shapeset;
1189  }
1190 
1191  space->precalculate_projection_matrix(2, space->proj_mat, space->chol_p);
1192  }
1193 
1194  else if (spaceType == HERMES_HCURL_SPACE)
1195  {
1196  space = new HcurlSpace<Scalar>();
1197  space->mesh = mesh;
1198 
1199  if (shapeset == nullptr)
1200  {
1201  space->shapeset = new HcurlShapeset;
1202  space->own_shapeset = true;
1203  }
1204  else
1205  {
1206  if (shapeset->get_num_components() < 2)
1207  throw Hermes::Exceptions::Exception("HcurlSpace requires a vector shapeset in Space::load.");
1208  if (shapeset->get_space_type() != HERMES_HCURL_SPACE)
1209  throw Hermes::Exceptions::SpaceLoadFailureException("Wrong shapeset / Wrong spaceType in Space loading subroutine.");
1210  else
1211  space->shapeset = shapeset;
1212  }
1213 
1214  space->precalculate_projection_matrix(0, space->proj_mat, space->chol_p);
1215  }
1216 
1217  else if (spaceType == HERMES_HDIV_SPACE)
1218  {
1219  space = new HdivSpace<Scalar>();
1220  space->mesh = mesh;
1221 
1222  if (shapeset == nullptr)
1223  {
1224  space->shapeset = new HdivShapeset;
1225  space->own_shapeset = true;
1226  }
1227  else
1228  {
1229  if (shapeset->get_num_components() < 2)
1230  throw Hermes::Exceptions::Exception("HdivSpace requires a vector shapeset in Space::load.");
1231  if (shapeset->get_space_type() != HERMES_HDIV_SPACE)
1232  throw Hermes::Exceptions::SpaceLoadFailureException("Wrong shapeset / Wrong spaceType in Space loading subroutine.");
1233  else
1234  space->shapeset = shapeset;
1235  }
1236 
1237  space->precalculate_projection_matrix(0, space->proj_mat, space->chol_p);
1238  }
1239 
1240  else if (spaceType == HERMES_L2_SPACE)
1241  {
1242  space = new L2Space<Scalar>();
1243  space->mesh = mesh;
1244 
1245  if (shapeset == nullptr)
1246  {
1247  space->shapeset = new L2Shapeset;
1248  space->own_shapeset = true;
1249  }
1250  {
1251  if (shapeset->get_space_type() != HERMES_L2_SPACE)
1252  throw Hermes::Exceptions::SpaceLoadFailureException("Wrong shapeset / Wrong spaceType in Space loading subroutine.");
1253  else
1254  space->shapeset = shapeset;
1255  }
1256  }
1257 
1258  else if (spaceType == HERMES_L2_MARKERWISE_CONST_SPACE)
1259  {
1260  space = new L2MarkerWiseConstSpace<Scalar>(mesh);
1261 
1262  if (shapeset)
1263  Hermes::Mixins::Loggable::Static::warn("L2MarkerWiseConstSpace does not need a shapeset when loading.");
1264  }
1265 
1266  else
1267  {
1268  throw Exceptions::SpaceLoadFailureException("Wrong spaceType in Space loading subroutine.");
1269  return nullptr;
1270  }
1271 
1272  return space;
1273  }
1274 
1275  template<typename Scalar>
1276  SpaceSharedPtr<Scalar> Space<Scalar>::load(const char *filename, MeshSharedPtr mesh, bool validate, EssentialBCs<Scalar>* essential_bcs, Shapeset* shapeset)
1277  {
1278  try
1279  {
1280  SpaceSharedPtr<Scalar> space(nullptr);
1281 
1282  ::xml_schema::flags parsing_flags = 0;
1283 
1284  if (!validate)
1285  parsing_flags = xml_schema::flags::dont_validate;
1286 
1287  std::auto_ptr<XMLSpace::space> parsed_xml_space(XMLSpace::space_(filename, parsing_flags));
1288 
1289  if (spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) == HERMES_H1_SPACE)
1290  space = new H1Space<Scalar>();
1291  else if (spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) == HERMES_HCURL_SPACE)
1292  space = new HcurlSpace<Scalar>();
1293  else if (spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) == HERMES_HDIV_SPACE)
1294  space = new HdivSpace<Scalar>();
1295  else if (spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) == HERMES_L2_SPACE)
1296  space = new L2Space<Scalar>();
1297  else if (spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) == HERMES_L2_MARKERWISE_CONST_SPACE)
1298  space = new L2MarkerWiseConstSpace<Scalar>(mesh);
1299  else
1300  throw Hermes::Exceptions::IOException(Exceptions::IOException::Read, filename);
1301 
1302  space->mesh = mesh;
1303  space->mesh_seq = space->mesh->get_seq();
1304  space->init(shapeset, 1, false);
1305 
1306  if (essential_bcs != nullptr && spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) != HERMES_L2_SPACE && spaceTypeFromString(parsed_xml_space->spaceType().get().c_str()) != HERMES_L2_MARKERWISE_CONST_SPACE)
1307  {
1308  space->essential_bcs = essential_bcs;
1309  for (typename std::vector<EssentialBoundaryCondition<Scalar>*>::const_iterator it = essential_bcs->begin(); it != essential_bcs->end(); it++)
1310  for (unsigned int i = 0; i < (*it)->markers.size(); i++)
1311  if (space->get_mesh()->boundary_markers_conversion.conversion_table_inverse.find((*it)->markers.at(i)) == space->get_mesh()->boundary_markers_conversion.conversion_table_inverse.end())
1312  throw Hermes::Exceptions::Exception("A boundary condition defined on a non-existent marker.");
1313  }
1314 
1315  space->resize_tables();
1316 
1317  // Element data //
1318  unsigned int elem_data_count = parsed_xml_space->element_data().size();
1319  for (unsigned int elem_data_i = 0; elem_data_i < elem_data_count; elem_data_i++)
1320  {
1321  space->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].order = parsed_xml_space->element_data().at(elem_data_i).ord();
1322  space->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].bdof = parsed_xml_space->element_data().at(elem_data_i).bd();
1323  space->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].n = parsed_xml_space->element_data().at(elem_data_i).n();
1324  space->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].changed_in_last_adaptation = parsed_xml_space->element_data().at(elem_data_i).chgd();
1325  }
1326 
1327  space->seq = g_space_seq++;
1328 
1329  space->assign_dofs();
1330 
1331  return space;
1332  }
1333  catch (const xml_schema::exception& e)
1334  {
1335  throw Hermes::Exceptions::SpaceLoadFailureException(e.what());
1336  }
1337  }
1338 
1339  template<typename Scalar>
1340  void Space<Scalar>::load(const char *filename)
1341  {
1342  try
1343  {
1344  ::xml_schema::flags parsing_flags = 0;
1345 
1346  if (!this->validate)
1347  parsing_flags = xml_schema::flags::dont_validate;
1348 
1349  std::auto_ptr<XMLSpace::space> parsed_xml_space(XMLSpace::space_(filename, parsing_flags));
1350 
1351  if (strcmp(parsed_xml_space->spaceType().get().c_str(), spaceTypeToString(this->get_type())))
1352  throw Exceptions::Exception("Saved Space is not of the same type as the current one in loading.");
1353 
1354  this->resize_tables();
1355 
1356  // Element data //
1357  unsigned int elem_data_count = parsed_xml_space->element_data().size();
1358  for (unsigned int elem_data_i = 0; elem_data_i < elem_data_count; elem_data_i++)
1359  {
1360  this->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].order = parsed_xml_space->element_data().at(elem_data_i).ord();
1361  this->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].bdof = parsed_xml_space->element_data().at(elem_data_i).bd();
1362  this->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].n = parsed_xml_space->element_data().at(elem_data_i).n();
1363  this->edata[parsed_xml_space->element_data().at(elem_data_i).e_id()].changed_in_last_adaptation = parsed_xml_space->element_data().at(elem_data_i).chgd();
1364  }
1365 
1366  this->seq = g_space_seq++;
1367 
1368  this->assign_dofs();
1369  }
1370  catch (const xml_schema::exception& e)
1371  {
1372  throw Hermes::Exceptions::SpaceLoadFailureException(e.what());
1373  }
1374  }
1375 
1376 #ifdef WITH_BSON
1377  template<typename Scalar>
1378  SpaceSharedPtr<Scalar> Space<Scalar>::load_bson(const char *filename, MeshSharedPtr mesh, EssentialBCs<Scalar>* essential_bcs, Shapeset* shapeset)
1379  {
1380  FILE *fpr;
1381  fpr = fopen(filename, "rb");
1382 
1383  // file size:
1384  fseek(fpr, 0, SEEK_END);
1385  int size = ftell(fpr);
1386  rewind(fpr);
1387 
1388  // allocate memory to contain the whole file:
1389  char *datar = malloc_with_check<char>(size);
1390  fread(datar, size, 1, fpr);
1391  fclose(fpr);
1392 
1393  bson br;
1394  bson_init_finished_data(&br, datar, 0);
1395 
1396  bson_iterator it;
1397  bson sub;
1398  bson_find(&it, &br, "type");
1399 
1400  SpaceSharedPtr<Scalar> space = Space<Scalar>::init_empty_space(spaceTypeFromString(bson_iterator_string(&it)), mesh, shapeset);
1401  space->mesh_seq = space->mesh->get_seq();
1402  space->resize_tables();
1403 
1404  // L2 space does not have any (strong) essential BCs.
1405  if (essential_bcs != nullptr && space->get_type() != HERMES_L2_SPACE && space->get_type() != HERMES_L2_MARKERWISE_CONST_SPACE)
1406  {
1407  space->essential_bcs = essential_bcs;
1408  for (typename std::vector<EssentialBoundaryCondition<Scalar>*>::const_iterator it = essential_bcs->begin(); it != essential_bcs->end(); it++)
1409  for (unsigned int i = 0; i < (*it)->markers.size(); i++)
1410  if (space->get_mesh()->boundary_markers_conversion.conversion_table_inverse.find((*it)->markers.at(i)) == space->get_mesh()->boundary_markers_conversion.conversion_table_inverse.end())
1411  throw Hermes::Exceptions::Exception("A boundary condition defined on a non-existent marker.");
1412  }
1413 
1414  // Element count.
1415  bson_find(&it, &br, "element_data_count");
1416  if (bson_iterator_int(&it) != mesh->get_max_element_id())
1417  throw Exceptions::Exception("Mesh and saved space mixed in Space<Scalar>::load_bson.");
1418 
1419  // coeffs
1420  bson_iterator it_coeffs;
1421  bson_find(&it_coeffs, &br, "orders");
1422  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1423  bson_iterator_init(&it, &sub);
1424  int index_coeff = 0;
1425  while (bson_iterator_next(&it))
1426  space->edata[index_coeff++].order = bson_iterator_int(&it);
1427 
1428  bson_find(&it_coeffs, &br, "bdofs");
1429  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1430  bson_iterator_init(&it, &sub);
1431  index_coeff = 0;
1432  while (bson_iterator_next(&it))
1433  space->edata[index_coeff++].bdof = bson_iterator_int(&it);
1434 
1435  bson_find(&it_coeffs, &br, "ns");
1436  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1437  bson_iterator_init(&it, &sub);
1438  index_coeff = 0;
1439  while (bson_iterator_next(&it))
1440  space->edata[index_coeff++].n = bson_iterator_int(&it);
1441 
1442  bson_find(&it_coeffs, &br, "changed");
1443  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1444  bson_iterator_init(&it, &sub);
1445  index_coeff = 0;
1446  while (bson_iterator_next(&it))
1447  space->edata[index_coeff++].changed_in_last_adaptation = bson_iterator_int(&it);
1448 
1449  bson_destroy(&br);
1450  free_with_check(datar);
1451 
1452  space->seq = g_space_seq++;
1453 
1454  space->assign_dofs();
1455 
1456  return space;
1457  }
1458 
1459  template<typename Scalar>
1460  void Space<Scalar>::load_bson(const char *filename)
1461  {
1462  FILE *fpr;
1463  fpr = fopen(filename, "rb");
1464 
1465  // file size:
1466  fseek(fpr, 0, SEEK_END);
1467  int size = ftell(fpr);
1468  rewind(fpr);
1469 
1470  // allocate memory to contain the whole file:
1471  char *datar = malloc_with_check<char>(size);
1472  fread(datar, size, 1, fpr);
1473  fclose(fpr);
1474 
1475  bson br;
1476  bson_init_finished_data(&br, datar, 0);
1477 
1478  bson_iterator it;
1479  bson sub;
1480  bson_find(&it, &br, "type");
1481 
1482  if (strcmp(bson_iterator_string(&it), spaceTypeToString(this->get_type())))
1483  throw Exceptions::Exception("Saved Space is not of the same type as the current one in loading.");
1484 
1485  // Element count.
1486  bson_find(&it, &br, "element_data_count");
1487  if (bson_iterator_int(&it) != mesh->get_max_element_id())
1488  throw Exceptions::Exception("Current and saved space mixed in Space<Scalar>::load_bson.");
1489 
1490  this->resize_tables();
1491 
1492  // coeffs
1493  bson_iterator it_coeffs;
1494  bson_find(&it_coeffs, &br, "orders");
1495  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1496  bson_iterator_init(&it, &sub);
1497  int index_coeff = 0;
1498  while (bson_iterator_next(&it))
1499  this->edata[index_coeff++].order = bson_iterator_int(&it);
1500 
1501  bson_find(&it_coeffs, &br, "bdofs");
1502  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1503  bson_iterator_init(&it, &sub);
1504  index_coeff = 0;
1505  while (bson_iterator_next(&it))
1506  this->edata[index_coeff++].bdof = bson_iterator_int(&it);
1507 
1508  bson_find(&it_coeffs, &br, "ns");
1509  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1510  bson_iterator_init(&it, &sub);
1511  index_coeff = 0;
1512  while (bson_iterator_next(&it))
1513  this->edata[index_coeff++].n = bson_iterator_int(&it);
1514 
1515  bson_find(&it_coeffs, &br, "changed");
1516  bson_iterator_subobject_init(&it_coeffs, &sub, 0);
1517  bson_iterator_init(&it, &sub);
1518  index_coeff = 0;
1519  while (bson_iterator_next(&it))
1520  this->edata[index_coeff++].changed_in_last_adaptation = bson_iterator_int(&it);
1521 
1522  bson_destroy(&br);
1523  free_with_check(datar);
1524 
1525  this->seq = g_space_seq++;
1526 
1527  this->assign_dofs();
1528  }
1529 #endif
1530 
1531  namespace Mixins
1532  {
1533  template<typename Scalar>
1534  std::vector<SpaceSharedPtr<Scalar> > SettableSpaces<Scalar>::get_spaces()
1535  {
1536  throw Hermes::Exceptions::MethodNotOverridenException("SettableSpaces<Scalar>::get_spaces()");
1537  }
1538 
1539  template<typename Scalar>
1541  {
1542  return this->get_spaces()[n];
1543  }
1544 
1545  template<typename Scalar>
1546  void SettableSpaces<Scalar>::set_space(SpaceSharedPtr<Scalar> space)
1547  {
1548  std::vector<SpaceSharedPtr<Scalar> > spaces;
1549  spaces.push_back(space);
1550  this->set_spaces(spaces);
1551  }
1552 
1553  template class HERMES_API SettableSpaces < double > ;
1554  template class HERMES_API SettableSpaces < std::complex<double> > ;
1555  }
1556 
1557  template class HERMES_API Space < double > ;
1558  template class HERMES_API Space < std::complex<double> > ;
1559 
1560  template class HERMES_API SpaceSharedPtr < double > ;
1561  template class HERMES_API SpaceSharedPtr < std::complex<double> > ;
1562  }
1563 }
::xsd::cxx::tree::id< char, ncname > id
C++ type corresponding to the ID XML Schema built-in type.
int first_dof
For equation systems.
Definition: space.h:372
H1ShapesetJacobi H1Shapeset
Experimental.
unsigned type
0 = vertex node; 1 = edge node
Definition: element.h:52
static const int H2D_UNASSIGNED_DOF
DOF which was not assigned yet.
Definition: space.h:354
int id
node id number
Definition: element.h:48
Definition: adapt.h:24
int ndof
Number of degrees of freedom (dimension of the space).
Definition: space.h:351
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
int get_bubble_functions_count()
Returns the total (global) number of bubble functions.
Definition: space.cpp:952
int marker
element marker
Definition: element.h:144
int id
element id number
Definition: element.h:112
virtual bool isOkay() const
State querying helpers.
Definition: space.cpp:147
void save(const char *filename) const
Saves this space into a file.
Definition: space.cpp:1097
::xsd::cxx::tree::flags flags
Parsing and serialization flags.
int vertex_functions_count
For statistics.
Definition: space.h:369
int mesh_seq
Tracking changes - mesh.
Definition: space.h:379
int get_edge_functions_count()
Returns the total (global) number of edge functions.
Definition: space.cpp:946
const spaceType_optional & spaceType() const
Return a read-only (constant) reference to the attribute container.
Stores one element of a mesh.
Definition: element.h:107
int get_element_order(int id) const
Returns element polynomial order.
Definition: space.h:154
HdivShapesetLegendre HdivShapeset
This is the default Hdiv shapeset typedef.
void free_bc_data()
Free BC data.
Definition: space.cpp:1086
int get_vertex_functions_count()
Definition: space.cpp:940
void set_uniform_order(int order, std::string marker=HERMES_ANY)
Definition: space.cpp:392
void init()
Common code for constructors.
Definition: space.cpp:85
Element * elem[2]
elements sharing the edge node
Definition: element.h:70
void get_boundary_assembly_list(Element *e, int surf_num, AsmList< Scalar > *al) const
Obtains an edge assembly list (contains shape functions that are nonzero on the specified edge)...
Definition: space.cpp:978
int get_max_dof() const
Returns the DOF number of the last basis function.
Definition: space.cpp:293
virtual ~Space()
Destructor.
Definition: space.cpp:182
void set_mesh(MeshSharedPtr mesh)
Sets a (new) mesh and calls assign_dofs().
Definition: space.cpp:812
virtual void get_element_assembly_list(Element *e, AsmList< Scalar > *al) const
Obtains an assembly list for the given element.
Definition: space.cpp:958
Generated from space_h2d_xml.xsd.
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
void add_triplet(int i, int d, Scalar c)
Adds a record for one basis function (shape functions index, basis functions index, coefficient).
Definition: asmlist.cpp:62
std::vector< Scalar * > bc_data_projections
Used for bc projection.
Definition: space.h:468
Used to pass the instances of Space around.
Definition: space.h:34
HcurlShapesetGradLeg HcurlShapeset
This is the default Hcurl shapeset typedef.
void free()
Freeing the data.
Definition: space.cpp:109
Stores one node of a mesh.
Definition: element.h:45
void adjust_element_order(int order_change, int min_order)
Definition: space.cpp:422
const element_data_sequence & element_data() const
Return a read-only (constant) reference to the element sequence.
::xsd::cxx::tree::time< char, simple_type > time
C++ type corresponding to the time XML Schema built-in type.
virtual int get_edge_order(Element *e, int edge) const
Internal. Obtains the order of an edge, according to the minimum rule.
Definition: space.cpp:769
virtual int get_edge_order_internal(Node *en) const
Internal.
Definition: space.cpp:783
static SpaceSharedPtr< Scalar > init_empty_space(SpaceType spaceType, MeshSharedPtr mesh, Shapeset *shapeset)
Definition: space.cpp:1169
virtual void copy(SpaceSharedPtr< Scalar > space, MeshSharedPtr new_mesh)
Definition: space.cpp:243
int get_num_dofs() const
Returns the number of basis functions contained in the space.
Definition: space.cpp:286
Determines the position on an element surface (edge in 2D and Face in 3D).
Definition: traverse.h:30
Node * en[H2D_MAX_NUMBER_EDGES]
edge node pointers
Definition: element.h:138
#define H2D_GET_H_ORDER(encoded_order)
Macros for combining quad horizontal and vertical encoded_orders.
Definition: global.h:98
void distribute_orders(MeshSharedPtr mesh, int *parents)
Sets polynomial orders to elements created by Mesh::regularize() using "parents". ...
Definition: space.cpp:846
virtual SpaceType get_space_type() const =0
virtual void handle_orders(SpaceSharedPtr< Scalar > ref_space)
Definition: space.cpp:605
::xsd::cxx::xml::dom::namespace_infomap< char > namespace_infomap
Namespace serialization information map.
unsigned short cnt
the number of items in the arrays idx, dof and coef
Definition: asmlist.h:54
unsigned int seq_assigned
Tracking changes - mark call to assign_dofs().
Definition: space.h:377
virtual void resize_tables()
Updates internal node and element tables.
Definition: space.cpp:206
virtual SpaceSharedPtr< Scalar > create_ref_space(bool assign_dofs=true)
Methods that user calls to get the reference space pointer (has to be properly casted if necessary)...
Definition: space.cpp:658
NodeData * ndata
node data table
Definition: space.h:424
Should be exactly the same as is the count of enum ShapesetType.
Definition: shapeset.h:95
unsigned bnd
1 = boundary node; 0 = inner node
Definition: element.h:54
void update_essential_bc_values()
Definition: space.cpp:1068
virtual int assign_dofs(int first_dof=0)
Builds basis functions and assigns DOF numbers to them.
Definition: space.cpp:864
EssentialBCs< Scalar > * get_essential_bcs() const
Obtains an boundary conditions.
Definition: space.cpp:312
void unrefine_all_mesh_elements(bool keep_initial_refinements=true)
Definition: space.cpp:579
Class corresponding to the element_data schema type.
int esize
element data table size
Definition: space.h:430
ElementData * edata
element data table
Definition: space.h:428
::xsd::cxx::tree::string< char, simple_type > string
C++ type corresponding to the string XML Schema built-in type.
unsigned char get_num_components() const
Returns 2 if this is a vector shapeset, 1 otherwise.
Definition: shapeset.cpp:195
int get_seq() const
Internal. Used by DiscreteProblem to detect changes in the space.
Definition: space.cpp:840
virtual void set_element_order_internal(int id, int order, int order_v=-1)
Definition: space.cpp:325
Represents a finite element space over a domain.
Definition: api2d.h:34
virtual void reset_dof_assignment()
Resets assignment of DOF to an unassigned state.
Definition: space.cpp:907
MeshSharedPtr mesh
FE mesh.
Definition: space.h:366
Class corresponding to the space schema type.
static SpaceSharedPtr< Scalar > load(const char *filename, MeshSharedPtr mesh, bool validate=false, EssentialBCs< Scalar > *essential_bcs=nullptr, Shapeset *shapeset=nullptr)
Loads a space from a file in XML format.
Definition: space.cpp:1276
Element * sons[H2D_MAX_ELEMENT_SONS]
son elements (up to four)
Definition: element.h:140
void set_uniform_order_internal(int order, int marker)
Definition: space.cpp:401
ReferenceSpaceCreator(unsigned int order_increase=1)
Definition: space.cpp:595
bool active
0 = active, no sons; 1 = inactive (refined), has sons
Definition: element.h:114
bool is_up_to_date() const
Returns true if the space is ready for computation, false otherwise.
Definition: space.cpp:306
int marker
edge marker
Definition: element.h:68
virtual void post_assign()
Definition: space.cpp:835
::std::auto_ptr< ::XMLSpace::space > space_(const ::std::string &uri,::xml_schema::flags f=0, const ::xml_schema::properties &p=::xml_schema::properties())
Parse a URI or a local file.
void set_mesh_seq(int seq)
Sets a (new) mesh seq, and mesh_seq.
Definition: space.cpp:823
EssentialBCs< Scalar > * essential_bcs
Boundary conditions.
Definition: space.h:363
void set_essential_bcs(EssentialBCs< Scalar > *essential_bcs)
Sets the boundary condition.
Definition: space.cpp:1001
unsigned int seq
Tracking changes.
Definition: space.h:375
L2ShapesetLegendre L2Shapeset
This is the default shapeset typedef.
virtual SpaceType get_type() const =0
Internal. Return type of this space. See enum SpaceType.
int nsize
node data table size
Definition: space.h:426
1D quadrature points on the standard reference domain (-1,1)
Definition: quad_all.h:28
virtual void set_element_order(int id, int order, int order_v=-1)
Definition: space.cpp:319
Node * vn[H2D_MAX_NUMBER_VERTICES]
vertex node pointers
Definition: element.h:134
void unrefine_all_mesh_elements_internal(bool keep_initial_refinements, bool only_unrefine_space_data)
Definition: space.cpp:468
virtual void update_constraints()
Definition: space.cpp:830