17 #include "projections/ogprojection.h"
18 #include "refinement_selectors/candidates.h"
19 #include "function/exact_solution.h"
25 template<
typename Scalar>
30 template<
typename Scalar>
33 if (processed_error_squared > (threshold*threshold) * error_calculator->get_total_error_squared())
39 template<
typename Scalar>
44 template<
typename Scalar>
48 if (*(element_reference.
error) > (threshold*threshold) * max_error_squared)
54 template<
typename Scalar>
59 template<
typename Scalar>
63 if (element_inspected_i == 0)
68 if (*(element_reference.
error) > (threshold*threshold) * *((previous_element_reference).error))
75 template<
typename Scalar>
82 template<
typename Scalar>
90 template<
typename Scalar>
93 this->set_space(space);
98 template<
typename Scalar>
101 if (!this->errorCalculator)
102 throw Exceptions::Exception(
"Error calculator must not be nullptr in Adapt::Adapt().");
104 this->num = spaces.size();
106 if (this->num > H2D_MAX_COMPONENTS)
107 throw Exceptions::ValueException(
"components", this->num, 0, H2D_MAX_COMPONENTS);
109 for (
unsigned int i = 0; i < this->num; i++)
112 throw Exceptions::NullException(0, i);
116 elements_to_refine =
nullptr;
119 template<
typename Scalar>
125 template<
typename Scalar>
128 free_with_check(elements_to_refine);
131 template<
typename Scalar>
134 this->spaces = spaces;
135 this->num = spaces.size();
138 this->meshes.clear();
139 for (
int i = 0; i < this->num; i++)
140 this->meshes.push_back(this->spaces[i]->get_mesh());
143 template<
typename Scalar>
146 this->spaces.clear();
147 this->spaces.push_back(space);
150 this->meshes.clear();
151 this->meshes.push_back(space->get_mesh());
154 template<
typename Scalar>
160 template<
typename Scalar>
163 this->strategy = strategy_;
166 template<
typename Scalar>
169 this->regularization = regularization_;
172 template<
typename Scalar>
175 if (!this->spaces.size())
177 this->info(
"\tAdaptivity: spaces are missing.");
183 this->info(
"\tAdaptivity: strategy is missing.");
189 template<
typename Scalar>
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);
206 for (
int j = 0; j < this->num; j++)
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);
213 if (elements_to_refine)
214 free_with_check(elements_to_refine);
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();
224 this->exceptionMessageCaughtInParallelBlock.clear();
227 template<
typename Scalar>
231 double processed_error_squared = 0.0;
233 double max_error_squared = *(this->errorCalculator->get_element_reference(0).error);
235 unsigned int attempted_element_refinements_count = 0;
239 for (
int element_inspected_i = 0; element_inspected_i < this->errorCalculator->num_act_elems; element_inspected_i++)
245 if (!this->strategy->add_refinement(this->errorCalculator, processed_error_squared, max_error_squared, element_inspected_i))
248 processed_error_squared += *(element_reference.
error);
250 attempted_element_refinements_count++;
253 return attempted_element_refinements_count;
256 template<
typename Scalar>
260 MeshSharedPtr meshes[H2D_MAX_COMPONENTS];
262 this->init_adapt(refinement_selectors, element_refinement_location, meshes);
265 int attempted_element_refinements_count = calculate_attempted_element_refinements_count();
269 this->info(
"\tAdaptivity: data preparation duration: %f s.", this->last());
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);
276 std::vector<MeshFunctionSharedPtr<Scalar> > rslns;
278 for (
unsigned int i = 0; i < this->num; i++)
292 rslns.push_back(this->errorCalculator->fine_solutions[i]);
296 #pragma omp parallel num_threads(this->num_threads_used)
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;
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());
309 for (
int id_to_refine = start; id_to_refine < end; 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);
323 if (refinement_selectors[component]->select_refinement(meshes[component]->get_element(element_id), current_order, current_rslns[component].
get(), elem_ref))
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];
333 catch (Hermes::Exceptions::Exception& e)
335 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
336 this->exceptionMessageCaughtInParallelBlock = e.info();
340 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
341 this->exceptionMessageCaughtInParallelBlock = e.what();
346 if (!this->exceptionMessageCaughtInParallelBlock.empty())
348 this->deinit_adapt(element_refinement_location);
349 throw Hermes::Exceptions::Exception(this->exceptionMessageCaughtInParallelBlock.c_str());
355 this->info(
"\tAdaptivity: refinement selection duration: %f s.", this->last());
358 fix_shared_mesh_refinements(meshes, elements_to_refine, attempted_element_refinements_count, element_refinement_location, &refinement_selectors.front());
361 apply_refinements(elements_to_refine, attempted_element_refinements_count);
366 this->deinit_adapt(element_refinement_location);
368 this->adapt_postprocess(meshes, attempted_element_refinements_count);
373 template<
typename Scalar>
377 for (
int j = 0; j < this->num; j++)
378 free_with_check(element_refinement_location[j]);
381 template<
typename Scalar>
385 if (this->regularization >= 0)
387 if (this->regularization == 0)
389 this->regularization = 1;
390 this->warn(
"Total mesh regularization is not supported in adaptivity. 1-irregular mesh is used instead.");
392 for (
int i = 0; i < this->num; i++)
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);
404 for (
unsigned int i = 0; i < this->spaces.size(); i++)
405 this->spaces[i]->assign_dofs();
408 for (
int i = 0; i < this->num; i++)
410 for_all_active_elements(e, this->meshes[i])
411 this->spaces[i]->edata[e->
id].changed_in_last_adaptation =
false;
415 for (
int i = 0; i < element_refinements_count; 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;
424 template<
typename Scalar>
430 if (refinementInfoMeshFunctionGlobal)
431 return refinementInfoMeshFunctionGlobal;
434 MeshSharedPtr union_mesh(
new Mesh);
435 Traverse::construct_union_mesh(this->num, &this->meshes[0], union_mesh);
437 int* info_array = calloc_with_check<Adapt<Scalar>,
int>(union_mesh->get_num_elements(),
this);
439 this->meshes.push_back(union_mesh);
441 unsigned int num_states;
443 #pragma omp parallel num_threads(this->num_threads_used)
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)
451 for (
int state_i = start; state_i < end; state_i++)
454 for (
int i = 0; i < this->elements_to_refine_count; i++)
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;
463 this->meshes.pop_back();
466 return refinementInfoMeshFunctionGlobal;
470 if (component >= this->num)
471 throw Exceptions::ValueException(
"component", component, this->num);
474 if (this->refinementInfoMeshFunction[component])
475 return this->refinementInfoMeshFunction[component];
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++)
481 if (this->elements_to_refine[i].comp == component)
484 info_array[this->elements_to_refine[i].id] = 2;
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;
494 return this->refinementInfoMeshFunction[component];
499 template<
typename Scalar>
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);
509 template<
typename Scalar>
517 std::vector<ElementToRefine> new_elems_to_refine;
519 for (
int inx = 0; inx < num_elem_to_proc; inx++)
527 for (
int j = 0; j < this->num; j++)
534 if (j != elem_ref.
comp && meshes[j]->get_seq() == meshes[elem_ref.
comp]->get_seq())
537 if (idx[j][elem_ref.
id])
544 selected_refinement = elem_ref_ii->
split;
556 if (elem_ref.
split != selected_refinement)
558 elem_ref.
split = selected_refinement;
563 for (
int j = 0; j < this->num; j++)
566 if (j != elem_ref.
comp && meshes[j]->get_seq() == meshes[elem_ref.
comp]->get_seq())
569 if (idx[j][elem_ref.
id])
572 if (elem_ref_ii->
split != selected_refinement)
574 elem_ref_ii->
split = selected_refinement;
581 this->warn(
"The best refinement poly degree is missing in fix_shared_mesh_refinements.");
590 elem_ref_new.
split = selected_refinement;
593 new_elems_to_refine.push_back(elem_ref_new);
601 if (new_elems_to_refine.size() > 0)
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;
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();
614 template<
typename Scalar>
618 for (
int i = 0; i < this->num; i++)
620 for_all_active_elements(e, meshes[i])
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);
625 for (
int j = 0; j < this->num; j++)
627 if ((j != i) && (meshes[j]->get_seq() == meshes[i]->get_seq()))
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));
635 this->spaces[i]->set_element_order_internal(e->
id, H2D_MAKE_QUAD_ORDER(current_order_h, current_order_v));
640 template<
typename Scalar>
643 for (
int i = 0; i < num_elem_to_process; i++)
644 apply_refinement(elems_to_refine[i]);
647 template<
typename Scalar>
655 Element* e = space->get_mesh()->get_element(elem_ref.
id);
660 space->edata[elem_ref.
id].changed_in_last_adaptation =
true;
665 space->get_mesh()->refine_element_id(elem_ref.
id);
666 for (
int j = 0; j < 4; j++)
669 space->edata[e->
sons[j]->
id].changed_in_last_adaptation =
true;
678 for (
int j = 0; j < 2; j++)
void init()
Common code for the constructors.
void set_spaces(std::vector< SpaceSharedPtr< Scalar > > spaces)
Set spaces.
unsigned short comp
An index of the component.
A reference to an element.
Stores one element of a mesh.
void init_adapt(std::vector< RefinementSelectors::Selector< Scalar > * > &refinement_selectors, ElementToRefine ***element_refinement_location, MeshSharedPtr *meshes)
Initialization.
Represents a finite element mesh. Typical usage: MeshSharedPtr mesh; Hermes::Hermes2D::MeshReaderH2DX...
void free()
Deallocates allocated private data.
MeshFunctionSharedPtr< double > get_refinementInfoMeshFunction(int component=-1)
bool adapt(std::vector< RefinementSelectors::Selector< Scalar > * > refinement_selectors)
Refines elements based on results from the ErrorCalculator class.
virtual ~Adapt()
Destructor. Deallocates allocated private data.
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
Used to pass the instances of Space around.
AdaptStoppingCriterionLevels(double threshold)
Constructor specifying the threshold (see description of threshold).
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.
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.
void set_strategy(AdaptivityStoppingCriterion< Scalar > *strategy)
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)
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.
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.
int calculate_attempted_element_refinements_count()
Return the number of element where a refinement will be sought.
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)
virtual bool isOkay() const
Internal checking.
void set_regularization_level(int regularization)
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)...
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.
void apply_refinement(const ElementToRefine &elem_ref)
Apply a single refinement.
Class for creating reference space.
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.
ANISO-refienement. The element is split along the horizontal axis. Quadrilaterals only...
A parent of all refinement selectors. Abstract class.
#define H2D_MAX_ELEMENT_SONS
Macros.
AdaptStoppingCriterionSingleElement(double threshold)
Constructor specifying the threshold (see description of threshold).
Element * sons[H2D_MAX_ELEMENT_SONS]
son elements (up to four)
AdaptStoppingCriterionCumulative(double threshold)
Constructor specifying the threshold (see description of threshold).
Class for creating reference mesh.
bool active
0 = active, no sons; 1 = inactive (refined), has sons
virtual MeshSharedPtr create_ref_mesh()
Represents the solution of a PDE.
void set_defaults()
Set default values.
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.
Element * parent
pointer to the parent element for the current son
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.
double * error
Pointer to the final error, respecting the errorType.
void deinit_adapt(ElementToRefine ***element_refinement_location)
Deinitialization.
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.