Hermes2D  3.0
error_thread_calculator.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/error_thread_calculator.h"
17 #include "discrete_problem/discrete_problem_helpers.h"
18 #include "discrete_problem/dg/multimesh_dg_neighbor_tree.h"
19 #include "neighbor_search.h"
20 #include "mesh/refmap.h"
21 #include "forms.h"
22 #include <stdlib.h>
23 
24 namespace Hermes
25 {
26  namespace Hermes2D
27  {
28  template<typename Scalar>
29  ErrorThreadCalculator<Scalar>::ErrorThreadCalculator(ErrorCalculator<Scalar>* errorCalculator) :
30  errorCalculator(errorCalculator)
31  {
32  slns = malloc_with_check<ErrorThreadCalculator<Scalar>, Solution<Scalar>*>(this->errorCalculator->component_count, this);
33  rslns = malloc_with_check<ErrorThreadCalculator<Scalar>, Solution<Scalar>*>(this->errorCalculator->component_count, this);
34 
35  for (int j = 0; j < this->errorCalculator->component_count; j++)
36  {
37  slns[j] = static_cast<Solution<Scalar>*>(errorCalculator->coarse_solutions[j]->clone());
38  rslns[j] = static_cast<Solution<Scalar>*>(errorCalculator->fine_solutions[j]->clone());
39  }
40  }
41 
42  template<typename Scalar>
43  ErrorThreadCalculator<Scalar>::~ErrorThreadCalculator()
44  {
45  this->free();
46  }
47 
48  template<typename Scalar>
49  void ErrorThreadCalculator<Scalar>::free()
50  {
51  for (int j = 0; j < this->errorCalculator->component_count; j++)
52  {
53  delete slns[j];
54  delete rslns[j];
55  }
56 
57  free_with_check(slns);
58  free_with_check(rslns);
59  }
60 
61  template<typename Scalar>
62  void ErrorThreadCalculator<Scalar>::evaluate_one_state(Traverse::State* current_state_)
63  {
64  this->current_state = current_state_;
65 
66  // Initialization.
67  for (int i = 0; i < this->errorCalculator->component_count; i++)
68  {
69  slns[i]->set_active_element(current_state->e[i]);
70  slns[i]->set_transform(current_state->sub_idx[i]);
71 
72  rslns[i]->set_active_element(current_state->e[this->errorCalculator->component_count + i]);
73  rslns[i]->set_transform(current_state->sub_idx[this->errorCalculator->component_count + i]);
74  }
75 
76  // Max order imposement.
77  int order = g_quad_2d_std.get_max_order(current_state->rep->get_mode());
78 
79  // Volumetric forms.
80  this->evaluate_volumetric_forms(current_state, order);
81 
82  // Surface forms.
83  if (current_state->isBnd && this->errorCalculator->mfsurf.size() > 0)
84  {
85  for (current_state->isurf = 0; current_state->isurf < current_state->rep->nvert; current_state->isurf++)
86  {
87  if (!current_state->bnd[current_state->isurf])
88  continue;
89 
90  this->evaluate_surface_forms_one_edge(current_state, order);
91  }
92  }
93 
94  // DG forms.
95  if (this->errorCalculator->mfDG.size() > 0)
96  {
97  for (current_state->isurf = 0; current_state->isurf < current_state->rep->nvert; current_state->isurf++)
98  {
99  if (current_state->bnd[current_state->isurf])
100  continue;
101 
102  ErrorThreadCalculator<Scalar>::DGErrorCalculator dGErrorCalculator(this);
103  dGErrorCalculator.assemble_one_edge();
104  }
105  }
106  }
107 
108  template<typename Scalar>
109  ErrorThreadCalculator<Scalar>::DGErrorCalculator::DGErrorCalculator(ErrorThreadCalculator* errorThreadCalculator) : errorThreadCalculator(errorThreadCalculator), current_state(errorThreadCalculator->current_state)
110  {
111  }
112 
113  template<typename Scalar>
115  {
116  this->neighbor_searches = malloc_with_check<ErrorThreadCalculator<Scalar>::DGErrorCalculator, NeighborSearch<Scalar>*>(this->current_state->num, this);
117 
118  // If this edge is an inter-element one on all meshes.
119  if (init_neighbors())
120  {
121  bool* dummy_processed;
122 
123  // Create a multimesh tree;
124  MultimeshDGNeighborTree<Scalar>::process_edge(this->neighbor_searches, this->current_state->num, this->num_neighbors, dummy_processed);
125 
126  for (unsigned int neighbor_i = 0; neighbor_i < num_neighbors; neighbor_i++)
127  this->assemble_one_neighbor(neighbor_i);
128 
129  free_with_check(dummy_processed);
130  }
131 
132  // Deinit neighbors.
133  free();
134  }
135 
136  template<typename Scalar>
138  {
139  // Initialize the NeighborSearches.
140  bool DG_intra = false;
141  for (unsigned int i = 0; i < current_state->num; i++)
142  {
143  bool existing_ns = false;
144  for (int j = i - 1; j >= 0; j--)
145  if (current_state->e[i] == current_state->e[j])
146  {
147  neighbor_searches[i] = neighbor_searches[j];
148  existing_ns = true;
149  break;
150  }
151  if (!existing_ns)
152  {
154  if (i < this->errorThreadCalculator->errorCalculator->component_count)
155  ns = new NeighborSearch<Scalar>(current_state->e[i], this->errorThreadCalculator->slns[i]->get_mesh());
156  else
157  ns = new NeighborSearch<Scalar>(current_state->e[i], this->errorThreadCalculator->rslns[i - this->errorThreadCalculator->errorCalculator->component_count]->get_mesh());
158 
159  ns->original_central_el_transform = current_state->sub_idx[i];
160  neighbor_searches[i] = ns;
161  if (neighbor_searches[i]->set_active_edge_multimesh(current_state->isurf))
162  DG_intra = true;
163  neighbor_searches[i]->clear_initial_sub_idx();
164  }
165  }
166 
167  return DG_intra;
168  }
169 
170  template<typename Scalar>
172  {
173  // Initialize the NeighborSearches.
174  for (unsigned int i = 0; i < current_state->num; i++)
175  {
176  bool existing_ns = false;
177  for (int j = i - 1; j >= 0; j--)
178  if (current_state->e[i] == current_state->e[j])
179  {
180  existing_ns = true;
181  break;
182  }
183  if (!existing_ns)
184  delete this->neighbor_searches[i];
185  }
186  free_with_check(neighbor_searches);
187  }
188 
189  template<typename Scalar>
190  void ErrorThreadCalculator<Scalar>::DGErrorCalculator::initialize_error_and_norm_functions(NormFormDG<Scalar>* mfs, DiscontinuousFunc<Scalar>* error_func[2], DiscontinuousFunc<Scalar>* norm_func[2])
191  {
192  switch (mfs->get_function_type())
193  {
194  case CoarseSolutions:
195  error_func[0] = neighbor_searches[mfs->i]->init_ext_fn(this->errorThreadCalculator->slns[mfs->i]);
196  if (mfs->i != mfs->j)
197  error_func[1] = neighbor_searches[mfs->j]->init_ext_fn(this->errorThreadCalculator->slns[mfs->j]);
198  else
199  error_func[1] = error_func[0];
200  norm_func[0] = error_func[0];
201  norm_func[1] = error_func[1];
202  break;
203  case FineSolutions:
204  error_func[0] = neighbor_searches[mfs->i + this->errorThreadCalculator->errorCalculator->component_count]->init_ext_fn(this->errorThreadCalculator->rslns[mfs->i]);
205  if (mfs->i != mfs->j)
206  error_func[1] = neighbor_searches[mfs->j + this->errorThreadCalculator->errorCalculator->component_count]->init_ext_fn(this->errorThreadCalculator->rslns[mfs->j]);
207  else
208  error_func[1] = error_func[0];
209  norm_func[0] = error_func[0];
210  norm_func[1] = error_func[1];
211  break;
212  case SolutionsDifference:
213  error_func[0] = neighbor_searches[mfs->i]->init_ext_fn(this->errorThreadCalculator->slns[mfs->i]);
214  norm_func[0] = neighbor_searches[mfs->i + this->errorThreadCalculator->errorCalculator->component_count]->init_ext_fn(this->errorThreadCalculator->rslns[mfs->i]);
215  error_func[0]->subtract(*norm_func[0]);
216  if (mfs->j != mfs->i)
217  {
218  error_func[1] = neighbor_searches[mfs->j]->init_ext_fn(this->errorThreadCalculator->slns[mfs->j]);
219  norm_func[1] = neighbor_searches[mfs->j + this->errorThreadCalculator->errorCalculator->component_count]->init_ext_fn(this->errorThreadCalculator->rslns[mfs->j]);
220  error_func[1]->subtract(*norm_func[1]);
221  }
222  else
223  {
224  error_func[1] = error_func[0];
225  norm_func[1] = norm_func[0];
226  }
227  break;
228  }
229  }
230 
231  template<typename Scalar>
232  void ErrorThreadCalculator<Scalar>::DGErrorCalculator::assemble_one_neighbor(unsigned int neighbor_i)
233  {
234  // Set the active segment in all NeighborSearches
235  for (unsigned int i = 0; i < this->current_state->num; i++)
236  {
237  NeighborSearch<Scalar>* ns = neighbor_searches[i];
238  ns->active_segment = neighbor_i;
239  ns->neighb_el = ns->neighbors[neighbor_i];
240  ns->neighbor_edge = ns->neighbor_edges[neighbor_i];
241  }
242 
243  // Push all the necessary transformations to all functions of this stage.
244  // The important thing is that the transformations to the current subelement are already there.
245  for (unsigned int fns_i = 0; fns_i < this->errorThreadCalculator->errorCalculator->component_count; fns_i++)
246  {
247  NeighborSearch<Scalar>* ns = neighbor_searches[fns_i];
248  if (ns->central_transformations[neighbor_i])
249  ns->central_transformations[neighbor_i]->apply_on(this->errorThreadCalculator->slns[fns_i]);
250 
251  ns = neighbor_searches[fns_i + this->errorThreadCalculator->errorCalculator->component_count];
252  if (ns->central_transformations[neighbor_i])
253  ns->central_transformations[neighbor_i]->apply_on(this->errorThreadCalculator->rslns[fns_i]);
254  }
255 
256  /***/
257  // The computation takes place here.
258  // Create the extended shapeset on the union of the central element and its current neighbor.
259  int order = 20;
260  int order_base = 20;
261 
262  for (int i = 0; i < this->errorThreadCalculator->errorCalculator->component_count; i++)
263  {
264  neighbor_searches[i]->set_quad_order(order);
265  neighbor_searches[i + this->errorThreadCalculator->errorCalculator->component_count]->set_quad_order(order);
266  }
267  order_base = order;
268 
269  RefMap** refmaps = malloc_with_check<ErrorThreadCalculator<Scalar>::DGErrorCalculator, RefMap*>(this->errorThreadCalculator->errorCalculator->component_count, this);
270  for (int i = 0; i < this->errorThreadCalculator->errorCalculator->component_count; i++)
271  refmaps[i] = this->errorThreadCalculator->slns[i]->get_refmap();
272  this->errorThreadCalculator->n_quadrature_points = init_surface_geometry_points_allocated(refmaps, this->errorThreadCalculator->errorCalculator->component_count, order_base, current_state->isurf, current_state->rep->marker, this->errorThreadCalculator->geometry_surf, this->errorThreadCalculator->jacobian_x_weights);
273  free_with_check(refmaps);
274 
275  for (unsigned short current_mfDG_i = 0; current_mfDG_i < this->errorThreadCalculator->errorCalculator->mfDG.size(); current_mfDG_i++)
276  {
277  NormFormDG<Scalar>* mfs = this->errorThreadCalculator->errorCalculator->mfDG[current_mfDG_i];
278 
279  double* error = &this->errorThreadCalculator->errorCalculator->errors[mfs->i][current_state->e[mfs->i]->id];
280  double* norm = &this->errorThreadCalculator->errorCalculator->norms[mfs->i][current_state->e[mfs->i]->id];
281 
282  DiscontinuousFunc<Scalar>* error_func[2];
283  DiscontinuousFunc<Scalar>* norm_func[2];
284 
285  this->initialize_error_and_norm_functions(mfs, error_func, norm_func);
286 
287  this->errorThreadCalculator->evaluate_DG_form(mfs, error_func[mfs->i], error_func[mfs->j], norm_func[mfs->i], norm_func[mfs->j], error, norm);
288 
289  // deinitialize Funcs
290  this->errorThreadCalculator->deinitialize_error_and_norm_functions(mfs, error_func, norm_func);
291  }
292 
293  // This is just cleaning after ourselves.
294  // Clear the transformations from the RefMaps and all functions.
295  for (unsigned int fns_i = 0; fns_i < this->errorThreadCalculator->errorCalculator->component_count; fns_i++)
296  {
297  this->errorThreadCalculator->slns[fns_i]->set_transform(neighbor_searches[fns_i]->original_central_el_transform);
298  this->errorThreadCalculator->rslns[fns_i]->set_transform(neighbor_searches[this->errorThreadCalculator->errorCalculator->component_count + fns_i]->original_central_el_transform);
299  }
300  }
301 
302  template<typename Scalar>
303  template<typename NormFormType>
304  void ErrorThreadCalculator<Scalar>::initialize_error_and_norm_functions(NormFormType* mf, Func<Scalar>* error_func[2], Func<Scalar>* norm_func[2], int order)
305  {
306  switch (mf->get_function_type())
307  {
308  case CoarseSolutions:
309  error_func[0] = init_fn(slns[mf->i], order);
310  if (mf->i != mf->j)
311  error_func[1] = init_fn(slns[mf->j], order);
312  else
313  error_func[1] = error_func[0];
314  norm_func[0] = error_func[0];
315  norm_func[1] = error_func[1];
316  break;
317  case FineSolutions:
318  error_func[0] = init_fn(rslns[mf->i], order);
319  if (mf->i != mf->j)
320  error_func[1] = init_fn(rslns[mf->j], order);
321  else
322  error_func[1] = error_func[0];
323  norm_func[0] = error_func[0];
324  norm_func[1] = error_func[1];
325  break;
326  case SolutionsDifference:
327  error_func[0] = init_fn(slns[mf->i], order);
328  norm_func[0] = init_fn(rslns[mf->i], order);
329  error_func[0]->subtract(norm_func[0]);
330  if (mf->j != mf->i)
331  {
332  error_func[1] = init_fn(slns[mf->j], order);
333  norm_func[1] = init_fn(rslns[mf->j], order);
334  error_func[1]->subtract(norm_func[1]);
335  }
336  else
337  {
338  error_func[1] = error_func[0];
339  norm_func[1] = norm_func[0];
340  }
341  break;
342  }
343  }
344 
345  template<typename Scalar>
346  template<typename NormFormType, typename FuncType>
347  void ErrorThreadCalculator<Scalar>::deinitialize_error_and_norm_functions(NormFormType* mf, FuncType* error_func[2], FuncType* norm_func[2])
348  {
349  switch (mf->get_function_type())
350  {
351  case CoarseSolutions:
352  case FineSolutions:
353  delete error_func[0];
354  if (mf->i != mf->j)
355  {
356  delete error_func[1];
357  }
358  break;
359  case SolutionsDifference:
360  delete error_func[0];
361  delete norm_func[0];
362  if (mf->i != mf->j)
363  {
364  delete error_func[1];
365  delete norm_func[1];
366  }
367  break;
368  }
369  }
370 
371  template<typename Scalar>
372  void ErrorThreadCalculator<Scalar>::evaluate_volumetric_forms(Traverse::State* current_state, int order)
373  {
374  // initialize points & geometry & jacobian times weights.
375  RefMap** refmaps = malloc_with_check<ErrorThreadCalculator<Scalar>, RefMap*>(this->errorCalculator->component_count, this);
376  for (int i = 0; i < this->errorCalculator->component_count; i++)
377  refmaps[i] = slns[i]->get_refmap();
378  this->n_quadrature_points = init_geometry_points_allocated(refmaps, this->errorCalculator->component_count, order, this->geometry_vol, this->jacobian_x_weights);
379 
380  free_with_check(refmaps);
381 
382  for (unsigned short i = 0; i < this->errorCalculator->mfvol.size(); i++)
383  {
384  NormFormVol<Scalar>* form = this->errorCalculator->mfvol[i];
385  double* error = &this->errorCalculator->errors[form->i][current_state->e[form->i]->id];
386  double* norm = &this->errorCalculator->norms[form->i][current_state->e[form->i]->id];
387 
388  Func<Scalar>* error_func[2];
389  Func<Scalar>* norm_func[2];
390 
391  this->initialize_error_and_norm_functions(form, error_func, norm_func, order);
392  this->evaluate_volumetric_form(form, error_func[0], error_func[1], norm_func[0], norm_func[1], error, norm);
393  this->deinitialize_error_and_norm_functions(form, error_func, norm_func);
394  }
395  }
396 
397  template<typename Scalar>
398  void ErrorThreadCalculator<Scalar>::evaluate_surface_forms_one_edge(Traverse::State* current_state, int order)
399  {
400  RefMap** refmaps = malloc_with_check<ErrorThreadCalculator<Scalar>, RefMap*>(this->errorCalculator->component_count, this);
401  for (int i = 0; i < this->errorCalculator->component_count; i++)
402  refmaps[i] = slns[i]->get_refmap();
403  this->n_quadrature_points = init_surface_geometry_points_allocated(refmaps, this->errorCalculator->component_count, order, current_state->isurf, current_state->rep->marker, this->geometry_surf, this->jacobian_x_weights);
404  free_with_check(refmaps);
405 
406  for (unsigned short i = 0; i < this->errorCalculator->mfsurf.size(); i++)
407  {
408  NormFormSurf<Scalar>* form = this->errorCalculator->mfsurf[i];
409 
410  bool assemble = false;
411  if (form->get_area() == HERMES_ANY)
412  assemble = true;
413  else
414  {
415  if (this->slns[form->i])
416  {
417  Mesh::MarkersConversion::StringValid marker_to_check = this->slns[form->i]->get_mesh()->get_boundary_markers_conversion().get_user_marker(current_state->e[form->i]->en[current_state->isurf]->marker);
418  if (marker_to_check.valid)
419  {
420  std::string marker = marker_to_check.marker;
421  if (form->get_area() == marker)
422  assemble = true;
423  }
424  }
425  if (this->rslns[form->i])
426  {
427  Mesh::MarkersConversion::StringValid marker_to_check = this->rslns[form->i]->get_mesh()->get_boundary_markers_conversion().get_user_marker(current_state->e[form->i]->en[current_state->isurf]->marker);
428  if (marker_to_check.valid)
429  {
430  std::string marker = marker_to_check.marker;
431  if (form->get_area() == marker)
432  assemble = true;
433  }
434  }
435  }
436 
437  if (!assemble)
438  continue;
439 
440  double* error = &this->errorCalculator->errors[form->i][current_state->e[form->i]->id];
441  double* norm = &this->errorCalculator->norms[form->i][current_state->e[form->i]->id];
442 
443  Func<Scalar>* error_func[2];
444  Func<Scalar>* norm_func[2];
445 
446  this->initialize_error_and_norm_functions(form, error_func, norm_func, order);
447  this->evaluate_surface_form(form, error_func[0], error_func[0], norm_func[1], norm_func[1], error, norm);
448  this->deinitialize_error_and_norm_functions(form, error_func, norm_func);
449  }
450  }
451 
452  template<typename Scalar>
453  void ErrorThreadCalculator<Scalar>::evaluate_volumetric_form(NormFormVol<Scalar>* form, Func<Scalar>* difference_func_i, Func<Scalar>* difference_func_j, Func<Scalar>* rsln_i, Func<Scalar>* rsln_j, double* error, double* norm)
454  {
455  double error_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, difference_func_i, difference_func_j, &this->geometry_vol));
456 #pragma omp atomic
457  (*error) += error_value;
458 
459  double norm_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, rsln_i, rsln_j, &this->geometry_vol));
460 
461 #pragma omp atomic
462  (*norm) += norm_value;
463  }
464 
465  template<typename Scalar>
466  void ErrorThreadCalculator<Scalar>::evaluate_surface_form(NormFormSurf<Scalar>* form, Func<Scalar>* difference_func_i, Func<Scalar>* difference_func_j, Func<Scalar>* rsln_i, Func<Scalar>* rsln_j, double* error, double* norm)
467  {
468  double error_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, difference_func_i, difference_func_j, &this->geometry_surf));
469 
470  // 1D quadrature has the weights summed to 2.
471  error_value *= 0.5;
472 
473 #pragma omp atomic
474  (*error) += error_value;
475 
476  double norm_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, rsln_i, rsln_j, &this->geometry_surf));
477 
478  // 1D quadrature has the weights summed to 2.
479  norm_value *= 0.5;
480 
481 #pragma omp atomic
482  (*norm) += norm_value;
483  }
484 
485  template<typename Scalar>
486  void ErrorThreadCalculator<Scalar>::evaluate_DG_form(NormFormDG<Scalar>* form, DiscontinuousFunc<Scalar>* difference_func_i, DiscontinuousFunc<Scalar>* difference_func_j, DiscontinuousFunc<Scalar>* rsln_i, DiscontinuousFunc<Scalar>* rsln_j, double* error, double* norm)
487  {
488  double error_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, difference_func_i, difference_func_j, &this->geometry_surf));
489 
490  // 1D quadrature has the weights summed to 2.
491  error_value *= 0.5;
492 
493 #pragma omp atomic
494  (*error) += error_value;
495 
496  double norm_value = std::abs(form->value(this->n_quadrature_points, this->jacobian_x_weights, rsln_i, rsln_j, &this->geometry_surf));
497 
498 #pragma omp atomic
499  (*norm) += norm_value;
500  }
501 
502  template HERMES_API class ErrorThreadCalculator < double > ;
503  template HERMES_API class ErrorThreadCalculator < std::complex<double> > ;
504  }
505 }
Definition: adapt.h:24
int marker
element marker
Definition: element.h:144
int id
element id number
Definition: element.h:112
static void process_edge(NeighborSearch< Scalar > **neighbor_searches, unsigned char num_neighbor_searches, unsigned int &num_neighbors, bool *&processed)
The main method, for the passed neighbor searches, it will process all multi-mesh neighbor consolidat...
HERMES_API Func< double > * init_fn(PrecalcShapeset *fu, RefMap *rm, const int order)
Init the shape function for the evaluation of the volumetric/surface integral (transformation of valu...
Definition: forms.cpp:469
uint64_t original_central_el_transform
Sub-element transformation of any function that comes from the.
::xsd::cxx::tree::string< char, simple_type > string
C++ type corresponding to the string XML Schema built-in type.
This class characterizes a neighborhood of a given edge in terms of adjacent elements and provides me...
::xsd::cxx::tree::error< char > error
Error condition.
HERMES_API unsigned char init_geometry_points_allocated(RefMap **reference_mapping, unsigned short reference_mapping_count, int order, GeomVol< double > &geometry, double *jacobian_x_weights)