Hermes2D  3.0
adapt.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 "adapt.h"
17 #include "projections/ogprojection.h"
18 #include "refinement_selectors/candidates.h"
19 #include "function/exact_solution.h"
20 
21 namespace Hermes
22 {
23  namespace Hermes2D
24  {
25  template<typename Scalar>
27  {
28  }
29 
30  template<typename Scalar>
31  bool AdaptStoppingCriterionCumulative<Scalar>::add_refinement(ErrorCalculator<Scalar>* error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
32  {
33  if (processed_error_squared > (threshold*threshold) * error_calculator->get_total_error_squared())
34  return false;
35  else
36  return true;
37  }
38 
39  template<typename Scalar>
41  {
42  }
43 
44  template<typename Scalar>
45  bool AdaptStoppingCriterionSingleElement<Scalar>::add_refinement(ErrorCalculator<Scalar>* error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
46  {
47  const typename ErrorCalculator<Scalar>::ElementReference& element_reference = error_calculator->get_element_reference(element_inspected_i);
48  if (*(element_reference.error) > (threshold*threshold) * max_error_squared)
49  return true;
50  else
51  return false;
52  }
53 
54  template<typename Scalar>
56  {
57  }
58 
59  template<typename Scalar>
60  bool AdaptStoppingCriterionLevels<Scalar>::add_refinement(ErrorCalculator<Scalar>* error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
61  {
62  const typename ErrorCalculator<Scalar>::ElementReference& element_reference = error_calculator->get_element_reference(element_inspected_i);
63  if (element_inspected_i == 0)
64  return true;
65  else
66  {
67  const typename ErrorCalculator<Scalar>::ElementReference previous_element_reference = error_calculator->get_element_reference(element_inspected_i - 1);
68  if (*(element_reference.error) > (threshold*threshold) * *((previous_element_reference).error))
69  return true;
70  else
71  return false;
72  }
73  }
74 
75  template<typename Scalar>
76  Adapt<Scalar>::Adapt(ErrorCalculator<Scalar>* errorCalculator, AdaptivityStoppingCriterion<Scalar>* strategy) : errorCalculator(errorCalculator), strategy(strategy)
77  {
78  this->init();
79  this->set_defaults();
80  }
81 
82  template<typename Scalar>
83  Adapt<Scalar>::Adapt(std::vector<SpaceSharedPtr<Scalar> > spaces_, ErrorCalculator<Scalar>* errorCalculator, AdaptivityStoppingCriterion<Scalar>* strategy) : errorCalculator(errorCalculator), strategy(strategy)
84  {
85  this->set_spaces(spaces_);
86  this->init();
87  this->set_defaults();
88  }
89 
90  template<typename Scalar>
91  Adapt<Scalar>::Adapt(SpaceSharedPtr<Scalar> space, ErrorCalculator<Scalar>* errorCalculator, AdaptivityStoppingCriterion<Scalar>* strategy) : errorCalculator(errorCalculator), strategy(strategy)
92  {
93  this->set_space(space);
94  this->init();
95  this->set_defaults();
96  }
97 
98  template<typename Scalar>
100  {
101  if (!this->errorCalculator)
102  throw Exceptions::Exception("Error calculator must not be nullptr in Adapt::Adapt().");
103 
104  this->num = spaces.size();
105 
106  if (this->num > H2D_MAX_COMPONENTS)
107  throw Exceptions::ValueException("components", this->num, 0, H2D_MAX_COMPONENTS);
108 
109  for (unsigned int i = 0; i < this->num; i++)
110  {
111  if (!spaces[i])
112  throw Exceptions::NullException(0, i);
113  spaces[i]->check();
114  }
115 
116  elements_to_refine = nullptr;
117  }
118 
119  template<typename Scalar>
121  {
122  this->free();
123  }
124 
125  template<typename Scalar>
127  {
128  free_with_check(elements_to_refine);
129  }
130 
131  template<typename Scalar>
133  {
134  this->spaces = spaces;
135  this->num = spaces.size();
136 
137  // Meshes.
138  this->meshes.clear();
139  for (int i = 0; i < this->num; i++)
140  this->meshes.push_back(this->spaces[i]->get_mesh());
141  }
142 
143  template<typename Scalar>
145  {
146  this->spaces.clear();
147  this->spaces.push_back(space);
148  this->num = 1;
149  // Meshes.
150  this->meshes.clear();
151  this->meshes.push_back(space->get_mesh());
152  }
153 
154  template<typename Scalar>
156  {
157  regularization = -1;
158  }
159 
160  template<typename Scalar>
162  {
163  this->strategy = strategy_;
164  }
165 
166  template<typename Scalar>
167  void Adapt<Scalar>::set_regularization_level(int regularization_)
168  {
169  this->regularization = regularization_;
170  }
171 
172  template<typename Scalar>
174  {
175  if (!this->spaces.size())
176  {
177  this->info("\tAdaptivity: spaces are missing.");
178  return false;
179  }
180 
181  if (!this->strategy)
182  {
183  this->info("\tAdaptivity: strategy is missing.");
184  return false;
185  }
186  return true;
187  }
188 
189  template<typename Scalar>
190  void Adapt<Scalar>::init_adapt(std::vector<RefinementSelectors::Selector<Scalar>*>& refinement_selectors, ElementToRefine*** element_refinement_location, MeshSharedPtr* meshes)
191  {
192  // Start time measurement.
193  this->tick();
194 
195  // Check.
196  this->check();
197 
198  // Checks.
199  if (!this->errorCalculator->elements_stored)
200  throw Exceptions::Exception("element errors have to be calculated first, call ErrorCalculator::calculate_errors().");
201  if (refinement_selectors.empty())
202  throw Exceptions::NullException(1);
203  Helpers::check_length(refinement_selectors, this->spaces);
204 
205  // Get meshes
206  for (int j = 0; j < this->num; j++)
207  {
208  meshes[j] = this->meshes[j];
209  element_refinement_location[j] = calloc_with_check<Adapt<Scalar>, ElementToRefine*>(meshes[j]->get_max_element_id() + 1, this);
210  }
211 
212  // Clearing.
213  if (elements_to_refine)
214  free_with_check(elements_to_refine);
215 
216  // Also handle the refinementInfoMeshFunctions.
217  if (this->refinementInfoMeshFunctionGlobal)
218  this->refinementInfoMeshFunctionGlobal.reset();
219  for (int i = 0; i < this->num; i++)
220  if (this->refinementInfoMeshFunction[i])
221  this->refinementInfoMeshFunction[i].reset();
222 
223  // Init the caught parallel exception message.
224  this->exceptionMessageCaughtInParallelBlock.clear();
225  }
226 
227  template<typename Scalar>
229  {
230  // Processed error so far.
231  double processed_error_squared = 0.0;
232  // Maximum error - the first one in the error calculator's array.
233  double max_error_squared = *(this->errorCalculator->get_element_reference(0).error);
234 
235  unsigned int attempted_element_refinements_count = 0;
236 
237  // For ALL elements on ALL meshes.
238  // The stopping condition for this loop is the stopping condition for adaptivity.
239  for (int element_inspected_i = 0; element_inspected_i < this->errorCalculator->num_act_elems; element_inspected_i++)
240  {
241  // Get the element info from the error calculator.
242  typename ErrorCalculator<Scalar>::ElementReference element_reference = this->errorCalculator->get_element_reference(element_inspected_i);
243 
244  // Ask the strategy if we should add this refinement or break the loop.
245  if (!this->strategy->add_refinement(this->errorCalculator, processed_error_squared, max_error_squared, element_inspected_i))
246  break;
247 
248  processed_error_squared += *(element_reference.error);
249 
250  attempted_element_refinements_count++;
251  }
252 
253  return attempted_element_refinements_count;
254  }
255 
256  template<typename Scalar>
257  bool Adapt<Scalar>::adapt(std::vector<RefinementSelectors::Selector<Scalar> *> refinement_selectors)
258  {
259  // Initialize.
260  MeshSharedPtr meshes[H2D_MAX_COMPONENTS];
261  ElementToRefine** element_refinement_location[H2D_MAX_COMPONENTS];
262  this->init_adapt(refinement_selectors, element_refinement_location, meshes);
263 
264  // This is the number of refinements attempted.
265  int attempted_element_refinements_count = calculate_attempted_element_refinements_count();
266 
267  // Time measurement.
268  this->tick();
269  this->info("\tAdaptivity: data preparation duration: %f s.", this->last());
270 
271  // List of indices of elements that are going to be processed
272  this->elements_to_refine_count = attempted_element_refinements_count;
273  this->elements_to_refine = malloc_with_check<Adapt<Scalar>, ElementToRefine>(elements_to_refine_count, this);
274 
275  // Projected solutions obtaining.
276  std::vector<MeshFunctionSharedPtr<Scalar> > rslns;
277 
278  for (unsigned int i = 0; i < this->num; i++)
279  {
280  if (dynamic_cast<ExactSolution<Scalar>*>(this->errorCalculator->fine_solutions[i].get()))
281  {
282  rslns.push_back(MeshFunctionSharedPtr<Scalar>(new Solution<Scalar>()));
283 
284  typename Mesh::ReferenceMeshCreator ref_mesh_creator(this->meshes[i]);
285  MeshSharedPtr ref_mesh = ref_mesh_creator.create_ref_mesh();
286  typename Space<Scalar>::ReferenceSpaceCreator ref_space_creator(this->spaces[i], ref_mesh);
287  SpaceSharedPtr<Scalar> ref_space = ref_space_creator.create_ref_space();
288 
289  OGProjection<Scalar>::project_global(ref_space, this->errorCalculator->fine_solutions[i], rslns[i]);
290  }
291  else
292  rslns.push_back(this->errorCalculator->fine_solutions[i]);
293  }
294 
295  // Parallel section
296 #pragma omp parallel num_threads(this->num_threads_used)
297  {
298  int thread_number = omp_get_thread_num();
299  int start = (attempted_element_refinements_count / this->num_threads_used) * thread_number;
300  int end = (attempted_element_refinements_count / this->num_threads_used) * (thread_number + 1);
301  if (thread_number == this->num_threads_used - 1)
302  end = attempted_element_refinements_count;
303 
304  // rslns cloning.
305  std::vector<MeshFunctionSharedPtr<Scalar> > current_rslns;
306  for (unsigned int i = 0; i < this->num; i++)
307  current_rslns.push_back(rslns[i]->clone());
308 
309  for (int id_to_refine = start; id_to_refine < end; id_to_refine++)
310  {
311  try
312  {
313  // Get the appropriate element reference from the error calculator.
314  typename ErrorCalculator<Scalar>::ElementReference element_reference = this->errorCalculator->get_element_reference(id_to_refine);
315  int element_id = element_reference.element_id;
316  int component = element_reference.comp;
317  int current_order = this->spaces[component]->get_element_order(element_id);
318 
319  // Get refinement suggestion.
320  ElementToRefine elem_ref(element_id, component);
321 
322  // Rsln[comp] may be unset if refinement_selectors[comp] == HOnlySelector or POnlySelector
323  if (refinement_selectors[component]->select_refinement(meshes[component]->get_element(element_id), current_order, current_rslns[component].get(), elem_ref))
324  {
325  // Put this refinement to the storage.
326  elem_ref.valid = true;
327  elements_to_refine[id_to_refine] = elem_ref;
328  element_refinement_location[component][element_id] = &elements_to_refine[id_to_refine];
329  }
330  else
331  elements_to_refine[id_to_refine] = ElementToRefine();
332  }
333  catch (Hermes::Exceptions::Exception& e)
334  {
335 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
336  this->exceptionMessageCaughtInParallelBlock = e.info();
337  }
338  catch (std::exception& e)
339  {
340 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
341  this->exceptionMessageCaughtInParallelBlock = e.what();
342  }
343  }
344  }
345 
346  if (!this->exceptionMessageCaughtInParallelBlock.empty())
347  {
348  this->deinit_adapt(element_refinement_location);
349  throw Hermes::Exceptions::Exception(this->exceptionMessageCaughtInParallelBlock.c_str());
350  return false;
351  }
352 
353  // Time measurement.
354  this->tick();
355  this->info("\tAdaptivity: refinement selection duration: %f s.", this->last());
356 
357  // Before applying, fix the shared mesh refinements.
358  fix_shared_mesh_refinements(meshes, elements_to_refine, attempted_element_refinements_count, element_refinement_location, &refinement_selectors.front());
359 
360  // Apply refinements
361  apply_refinements(elements_to_refine, attempted_element_refinements_count);
362 
363  // in singlemesh case, impose same orders across meshes
364  // homogenize_shared_mesh_orders(meshes);
365 
366  this->deinit_adapt(element_refinement_location);
367 
368  this->adapt_postprocess(meshes, attempted_element_refinements_count);
369 
370  return false;
371  }
372 
373  template<typename Scalar>
374  void Adapt<Scalar>::deinit_adapt(ElementToRefine*** element_refinement_location)
375  {
376  // Free data.
377  for (int j = 0; j < this->num; j++)
378  free_with_check(element_refinement_location[j]);
379  }
380 
381  template<typename Scalar>
382  void Adapt<Scalar>::adapt_postprocess(MeshSharedPtr* meshes, int element_refinements_count)
383  {
384  // mesh regularization
385  if (this->regularization >= 0)
386  {
387  if (this->regularization == 0)
388  {
389  this->regularization = 1;
390  this->warn("Total mesh regularization is not supported in adaptivity. 1-irregular mesh is used instead.");
391  }
392  for (int i = 0; i < this->num; i++)
393  {
394  int* parents;
395  parents = meshes[i]->regularize(this->regularization);
396  for (int j = 0; j < this->num; j++)
397  if (this->meshes[i]->get_seq() == this->meshes[j]->get_seq())
398  this->spaces[j]->distribute_orders(meshes[i], parents);
399  free_with_check(parents);
400  }
401  }
402 
403  // since space changed, assign dofs:
404  for (unsigned int i = 0; i < this->spaces.size(); i++)
405  this->spaces[i]->assign_dofs();
406 
407  Element* e;
408  for (int i = 0; i < this->num; i++)
409  {
410  for_all_active_elements(e, this->meshes[i])
411  this->spaces[i]->edata[e->id].changed_in_last_adaptation = false;
412  }
413 
414  // EXTREMELY important - set the changed_in_last_adaptation to changed elements.
415  for (int i = 0; i < element_refinements_count; i++)
416  {
417  typename ErrorCalculator<Scalar>::ElementReference element_reference = this->errorCalculator->get_element_reference(i);
418  int element_id = element_reference.element_id;
419  int component = element_reference.comp;
420  this->spaces[component]->edata[element_id].changed_in_last_adaptation = true;
421  }
422  }
423 
424  template<typename Scalar>
426  {
427  if (component == -1)
428  {
429  // The value is ready to be returned if it has been initialized and no other adaptivity run has been performed since.
430  if (refinementInfoMeshFunctionGlobal)
431  return refinementInfoMeshFunctionGlobal;
432 
433  // Union mesh preparation.
434  MeshSharedPtr union_mesh(new Mesh);
435  Traverse::construct_union_mesh(this->num, &this->meshes[0], union_mesh);
436  // Allocate union mesh element count to info array.
437  int* info_array = calloc_with_check<Adapt<Scalar>, int>(union_mesh->get_num_elements(), this);
438  // Traverse
439  this->meshes.push_back(union_mesh);
440  Traverse trav(this->meshes.size());
441  unsigned int num_states;
442  Traverse::State** states = trav.get_states(meshes, num_states);
443 #pragma omp parallel num_threads(this->num_threads_used)
444  {
445  int thread_number = omp_get_thread_num();
446  int start = (num_states / this->num_threads_used) * thread_number;
447  int end = (num_states / this->num_threads_used) * (thread_number + 1);
448  if (thread_number == this->num_threads_used - 1)
449  end = num_states;
450 
451  for (int state_i = start; state_i < end; state_i++)
452  {
453  Traverse::State* current_state = states[state_i];
454  for (int i = 0; i < this->elements_to_refine_count; i++)
455  {
456  Element* current_element = current_state->e[this->elements_to_refine[i].comp];
457  if (this->elements_to_refine[i].id == current_element->id || (current_element->parent && this->elements_to_refine[i].id == current_element->parent->id))
458  info_array[current_state->e[this->num]->id] = this->elements_to_refine[i].split;
459  }
460  }
461  }
462 
463  this->meshes.pop_back();
464 
465  refinementInfoMeshFunctionGlobal.reset(new ExactSolutionConstantArray<double, int>(union_mesh, info_array, true));
466  return refinementInfoMeshFunctionGlobal;
467  }
468  else
469  {
470  if (component >= this->num)
471  throw Exceptions::ValueException("component", component, this->num);
472 
473  // The value is ready to be returned if it has been initialized and no other adaptivity run has been performed since.
474  if (this->refinementInfoMeshFunction[component])
475  return this->refinementInfoMeshFunction[component];
476  else
477  {
478  int* info_array = calloc_with_check<Adapt<Scalar>, int>(this->spaces[component]->get_mesh()->get_num_elements(), this);
479  for (int i = 0; i < this->elements_to_refine_count; i++)
480  {
481  if (this->elements_to_refine[i].comp == component)
482  {
483  if (this->elements_to_refine[i].split == H2D_REFINEMENT_P)
484  info_array[this->elements_to_refine[i].id] = 2;
485  else
486  {
487  for (int sons_i = 0; sons_i < H2D_MAX_ELEMENT_SONS; sons_i++)
488  if (this->spaces[component]->get_mesh()->get_element(this->elements_to_refine[i].id)->sons[sons_i])
489  info_array[this->spaces[component]->get_mesh()->get_element(this->elements_to_refine[i].id)->sons[sons_i]->id] = this->elements_to_refine[i].split == H2D_REFINEMENT_H ? 1 : 2;
490  }
491  }
492  }
493  this->refinementInfoMeshFunction[component].reset(new ExactSolutionConstantArray<double, int>(spaces[component]->get_mesh(), info_array, true));
494  return this->refinementInfoMeshFunction[component];
495  }
496  }
497  }
498 
499  template<typename Scalar>
501  {
502  if (!refinement_selector)
503  throw Exceptions::NullException(1);
504  std::vector<RefinementSelectors::Selector<Scalar> *> refinement_selectors;
505  refinement_selectors.push_back(refinement_selector);
506  return adapt(refinement_selectors);
507  }
508 
509  template<typename Scalar>
510  void Adapt<Scalar>::fix_shared_mesh_refinements(MeshSharedPtr* meshes, ElementToRefine*& elems_to_refine, int& num_elem_to_proc, ElementToRefine*** idx, RefinementSelectors::Selector<Scalar>** refinement_selectors)
511  {
512  // Simple returns.
513  if (this->num == 1)
514  return;
515 
516  // For additions.
517  std::vector<ElementToRefine> new_elems_to_refine;
518 
519  for (int inx = 0; inx < num_elem_to_proc; inx++)
520  {
521  ElementToRefine& elem_ref = elems_to_refine[inx];
522  if (!elem_ref.valid)
523  continue;
524 
525  //select a refinement used by all components that share a mesh which is about to be refined
526  RefinementType selected_refinement = elem_ref.split;
527  for (int j = 0; j < this->num; j++)
528  {
529  if (selected_refinement == H2D_REFINEMENT_H)
530  // iso refinement is max what can be recieved
531  break;
532 
533  // if a mesh is shared
534  if (j != elem_ref.comp && meshes[j]->get_seq() == meshes[elem_ref.comp]->get_seq())
535  {
536  // and the sample element is about to be refined by another compoment
537  if (idx[j][elem_ref.id])
538  {
539  ElementToRefine* elem_ref_ii = idx[j][elem_ref.id];
540  //select more complicated refinement
541  if ((elem_ref_ii->split != selected_refinement) && (elem_ref_ii->split != H2D_REFINEMENT_P))
542  {
543  if ((elem_ref_ii->split == H2D_REFINEMENT_H_ANISO_H || elem_ref_ii->split == H2D_REFINEMENT_H_ANISO_V) && selected_refinement == H2D_REFINEMENT_P)
544  selected_refinement = elem_ref_ii->split;
545  else
546  selected_refinement = H2D_REFINEMENT_H;
547  }
548  }
549  }
550  }
551 
552  //fix other refinements according to the selected refinement
553  if (selected_refinement != H2D_REFINEMENT_P)
554  {
555  // change currently processed refinement
556  if (elem_ref.split != selected_refinement)
557  {
558  elem_ref.split = selected_refinement;
560  }
561 
562  //update orders
563  for (int j = 0; j < this->num; j++)
564  {
565  // if components share the mesh
566  if (j != elem_ref.comp && meshes[j]->get_seq() == meshes[elem_ref.comp]->get_seq())
567  {
568  // change other refinements
569  if (idx[j][elem_ref.id])
570  {
571  ElementToRefine* elem_ref_ii = idx[j][elem_ref.id];
572  if (elem_ref_ii->split != selected_refinement)
573  {
574  elem_ref_ii->split = selected_refinement;
575  if (elem_ref_ii->best_refinement_polynomial_order_type[selected_refinement])
577  else
578  {
579  // This should occur only if the original refinement was a p-refinement.
580 #ifdef _DEBUG
581  this->warn("The best refinement poly degree is missing in fix_shared_mesh_refinements.");
582 #endif
583  elem_ref_ii->refinement_polynomial_order[3] = elem_ref_ii->refinement_polynomial_order[2] = elem_ref_ii->refinement_polynomial_order[1] = elem_ref_ii->refinement_polynomial_order[0];
584  }
585  }
586  }
587  else
588  { // element (of the other comp.) not refined at all: assign refinement
589  ElementToRefine elem_ref_new(elem_ref.id, j);
590  elem_ref_new.split = selected_refinement;
591  for (int k = 0; k < H2D_MAX_ELEMENT_SONS; k++)
592  elem_ref_new.refinement_polynomial_order[k] = this->spaces[j]->get_element_order(elem_ref.id);
593  new_elems_to_refine.push_back(elem_ref_new);
594  }
595  }
596  }
597  }
598  }
599 
600  // Adding the additions.
601  if (new_elems_to_refine.size() > 0)
602  {
603  ElementToRefine* new_elems_to_refine_array = malloc_with_check<Adapt<Scalar>, ElementToRefine>(num_elem_to_proc + new_elems_to_refine.size(), this);
604  memcpy(new_elems_to_refine_array, elems_to_refine, num_elem_to_proc * sizeof(ElementToRefine));
605  free_with_check(elems_to_refine);
606  elems_to_refine = new_elems_to_refine_array;
607 
608  for (unsigned short inx = 0; inx < new_elems_to_refine.size(); inx++)
609  elems_to_refine[num_elem_to_proc + inx] = new_elems_to_refine[inx];
610  num_elem_to_proc += new_elems_to_refine.size();
611  }
612  }
613 
614  template<typename Scalar>
616  {
617  Element* e;
618  for (int i = 0; i < this->num; i++)
619  {
620  for_all_active_elements(e, meshes[i])
621  {
622  int current_quad_order = this->spaces[i]->get_element_order(e->id);
623  int current_order_h = H2D_GET_H_ORDER(current_quad_order), current_order_v = H2D_GET_V_ORDER(current_quad_order);
624 
625  for (int j = 0; j < this->num; j++)
626  {
627  if ((j != i) && (meshes[j]->get_seq() == meshes[i]->get_seq()))
628  {
629  int quad_order = this->spaces[j]->get_element_order(e->id);
630  current_order_h = std::max(current_order_h, H2D_GET_H_ORDER(quad_order));
631  current_order_v = std::max(current_order_v, H2D_GET_V_ORDER(quad_order));
632  }
633  }
634 
635  this->spaces[i]->set_element_order_internal(e->id, H2D_MAKE_QUAD_ORDER(current_order_h, current_order_v));
636  }
637  }
638  }
639 
640  template<typename Scalar>
641  void Adapt<Scalar>::apply_refinements(ElementToRefine* elems_to_refine, int num_elem_to_process)
642  {
643  for (int i = 0; i < num_elem_to_process; i++)
644  apply_refinement(elems_to_refine[i]);
645  }
646 
647  template<typename Scalar>
649  {
650  if (!elem_ref.valid)
651  return;
652 
653  SpaceSharedPtr<Scalar> space = this->spaces[elem_ref.comp];
654 
655  Element* e = space->get_mesh()->get_element(elem_ref.id);
656 
657  if (elem_ref.split == H2D_REFINEMENT_P)
658  {
659  space->set_element_order_internal(elem_ref.id, elem_ref.refinement_polynomial_order[0]);
660  space->edata[elem_ref.id].changed_in_last_adaptation = true;
661  }
662  else if (elem_ref.split == H2D_REFINEMENT_H)
663  {
664  if (e->active)
665  space->get_mesh()->refine_element_id(elem_ref.id);
666  for (int j = 0; j < 4; j++)
667  {
668  space->set_element_order_internal(e->sons[j]->id, elem_ref.refinement_polynomial_order[j]);
669  space->edata[e->sons[j]->id].changed_in_last_adaptation = true;
670  }
671  }
672  else
673  {
674  if (e->active)
675  {
676  space->get_mesh()->refine_element_id(elem_ref.id, (elem_ref.split == H2D_REFINEMENT_H_ANISO_H ? 1 : 2));
677  }
678  for (int j = 0; j < 2; j++)
679  {
680  space->set_element_order_internal(e->sons[(elem_ref.split == H2D_REFINEMENT_H_ANISO_H) ? j : j + 2]->id, elem_ref.refinement_polynomial_order[j]);
681  space->edata[e->sons[(elem_ref.split == H2D_REFINEMENT_H_ANISO_H) ? j : j + 2]->id].changed_in_last_adaptation = true;
682  }
683  }
684  }
685 
686  template HERMES_API class AdaptStoppingCriterionCumulative < double > ;
687  template HERMES_API class AdaptStoppingCriterionCumulative < std::complex<double> > ;
688  template HERMES_API class AdaptStoppingCriterionSingleElement < double > ;
690  template HERMES_API class AdaptStoppingCriterionLevels < double > ;
691  template HERMES_API class AdaptStoppingCriterionLevels < std::complex<double> > ;
692 
693  template HERMES_API class Adapt < double > ;
694  template HERMES_API class Adapt < std::complex<double> > ;
695  }
696 }
Definition: adapt.h:24
void init()
Common code for the constructors.
Definition: adapt.cpp:99
void set_spaces(std::vector< SpaceSharedPtr< Scalar > > spaces)
Set spaces.
Definition: adapt.cpp:132
unsigned short comp
An index of the component.
int id
element id number
Definition: element.h:112
Stores one element of a mesh.
Definition: element.h:107
void init_adapt(std::vector< RefinementSelectors::Selector< Scalar > * > &refinement_selectors, ElementToRefine ***element_refinement_location, MeshSharedPtr *meshes)
Initialization.
Definition: adapt.cpp:190
Represents a finite element mesh. Typical usage: MeshSharedPtr mesh; Hermes::Hermes2D::MeshReaderH2DX...
Definition: mesh.h:61
void free()
Deallocates allocated private data.
Definition: adapt.cpp:126
MeshFunctionSharedPtr< double > get_refinementInfoMeshFunction(int component=-1)
Definition: adapt.cpp:425
bool adapt(std::vector< RefinementSelectors::Selector< Scalar > * > refinement_selectors)
Refines elements based on results from the ErrorCalculator class.
Definition: adapt.cpp:257
virtual ~Adapt()
Destructor. Deallocates allocated private data.
Definition: adapt.cpp:120
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
Used to pass the instances of Space around.
Definition: space.h:34
AdaptStoppingCriterionLevels(double threshold)
Constructor specifying the threshold (see description of threshold).
Definition: adapt.cpp:55
bool add_refinement(ErrorCalculator< Scalar > *error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
Decide if the refinement at hand will be carried out.
Definition: adapt.cpp:60
RefinementType
Possible refinements of an element.
void adapt_postprocess(MeshSharedPtr *meshes, int element_refinements_count)
Handle meshes and spaces at the end of the routine.
Definition: adapt.cpp:382
void set_strategy(AdaptivityStoppingCriterion< Scalar > *strategy)
Definition: adapt.cpp:161
unsigned short refinement_polynomial_order[H2D_MAX_ELEMENT_SONS]
Encoded orders of sons.
bool add_refinement(ErrorCalculator< Scalar > *error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
Definition: adapt.cpp:31
ANISO-refienement. The element is split along the vertical axis. Quadrilaterals only.
static void copy_orders(unsigned short *dest, const unsigned short *src)
Copies array of orders.
RefinementType split
Proposed refinement. Possible values are defined in the enum RefinementType.
#define H2D_GET_H_ORDER(encoded_order)
Macros for combining quad horizontal and vertical encoded_orders.
Definition: global.h:98
int comp
A component which this element belongs to. Invalid if below 0.
virtual void apply_refinements(ElementToRefine *elems_to_refine, int num_elem_to_process)
Apply a vector of refinements.
Definition: adapt.cpp:641
int calculate_attempted_element_refinements_count()
Return the number of element where a refinement will be sought.
Definition: adapt.cpp:228
const ElementReference & get_element_reference(unsigned int id) const
A queue of elements which should be processes. The queue had to be filled by the method fill_regular_...
Adapt(std::vector< SpaceSharedPtr< Scalar > > spaces, ErrorCalculator< Scalar > *error_calculator, AdaptivityStoppingCriterion< Scalar > *strategy=nullptr)
Definition: adapt.cpp:83
virtual bool isOkay() const
Internal checking.
Definition: adapt.cpp:173
void set_regularization_level(int regularization)
Definition: adapt.cpp:167
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
int id
An ID of the element.
int element_id
An element ID. Invalid if below 0.
Represents an exact solution of a PDE.
Evaluation of an error between a (coarse) solution and a reference solution.
Definition: adapt.h:28
void apply_refinement(const ElementToRefine &elem_ref)
Apply a single refinement.
Definition: adapt.cpp:648
Class for creating reference space.
Definition: space.h:296
bool add_refinement(ErrorCalculator< Scalar > *error_calculator, double processed_error_squared, double max_error_squared, int element_inspected_i)
Decide if the refinement at hand will be carried out.
Definition: adapt.cpp:45
ANISO-refienement. The element is split along the horizontal axis. Quadrilaterals only...
A parent of all refinement selectors. Abstract class.
Definition: function.h:29
#define H2D_MAX_ELEMENT_SONS
Macros.
Definition: global.h:30
AdaptStoppingCriterionSingleElement(double threshold)
Constructor specifying the threshold (see description of threshold).
Definition: adapt.cpp:40
Element * sons[H2D_MAX_ELEMENT_SONS]
son elements (up to four)
Definition: element.h:140
AdaptStoppingCriterionCumulative(double threshold)
Constructor specifying the threshold (see description of threshold).
Definition: adapt.cpp:26
Class for creating reference mesh.
Definition: mesh.h:209
bool active
0 = active, no sons; 1 = inactive (refined), has sons
Definition: element.h:114
virtual MeshSharedPtr create_ref_mesh()
Definition: mesh.cpp:60
Represents the solution of a PDE.
Definition: api2d.h:35
void set_defaults()
Set default values.
Definition: adapt.cpp:155
void fix_shared_mesh_refinements(MeshSharedPtr *meshes, ElementToRefine *&elems_to_refine, int &num_elem_to_process, ElementToRefine ***refinement_location, RefinementSelectors::Selector< Scalar > **refinement_selectors)
Fixes refinements of a mesh which is shared among multiple components of a multimesh.
Definition: adapt.cpp:510
Element * parent
pointer to the parent element for the current son
Definition: element.h:118
unsigned short best_refinement_polynomial_order_type[4][H2D_MAX_ELEMENT_SONS]
void homogenize_shared_mesh_orders(MeshSharedPtr *meshes)
Enforces the same order to an element of a mesh which is shared among multiple components.
Definition: adapt.cpp:615
double * error
Pointer to the final error, respecting the errorType.
void deinit_adapt(ElementToRefine ***element_refinement_location)
Deinitialization.
Definition: adapt.cpp:374
static void project_global(SpaceSharedPtr< Scalar > space, MatrixFormVol< Scalar > *custom_projection_jacobian, VectorFormVol< Scalar > *custom_projection_residual, Scalar *target_vec)
This method allows to specify your own OG-projection form.