Hermes2D  3.0
postprocessing.cpp
1 #include "postprocessing.h"
2 #include "../space/space.h"
3 #include "../function/solution.h"
4 #include "refmap.h"
5 #include "forms.h"
6 #include "limit_order.h"
7 #include "discrete_problem/discrete_problem_helpers.h"
8 
9 namespace Hermes
10 {
11  namespace Hermes2D
12  {
13  namespace PostProcessing
14  {
15  bool VertexBasedLimiter::wider_bounds_on_boundary = false;
16 
17  template<typename Scalar>
18  Limiter<Scalar>::Limiter(SpaceSharedPtr<Scalar> space, Scalar* solution_vector) : component_count(1)
19  {
20  spaces.push_back(space);
21  this->init(solution_vector);
22  }
23 
24  template<typename Scalar>
25  Limiter<Scalar>::Limiter(std::vector<SpaceSharedPtr<Scalar> > spaces, Scalar* solution_vector) : spaces(spaces), component_count(spaces.size())
26  {
27  this->init(solution_vector);
28  }
29 
30  template<typename Scalar>
31  void Limiter<Scalar>::init(Scalar* solution_vector_)
32  {
33  if (solution_vector_)
34  {
35  try
36  {
37  int ndof = Space<Scalar>::get_num_dofs(this->spaces);
38  Scalar value = solution_vector_[ndof - 1];
39 
40  this->solution_vector = new Scalar[Space<Scalar>::get_num_dofs(this->spaces)];
41  memcpy(this->solution_vector, solution_vector_, sizeof(Scalar)* Space<Scalar>::get_num_dofs(this->spaces));
42  }
43  catch (...)
44  {
45  throw Exceptions::Exception("Wrong combination of space(s) and solution_vector passed to Limiter().");
46  }
47  }
48  }
49 
50  template<typename Scalar>
51  Limiter<Scalar>::~Limiter()
52  {
53  if (this->solution_vector)
54  delete[] this->solution_vector;
55  }
56 
57  template<typename Scalar>
59  {
60  // A check.
61  warn_if(this->component_count > 1, "One solution asked from a Limiter, but multiple solutions exist for limiting.");
62 
64  std::vector<MeshFunctionSharedPtr<Scalar> > solutions;
65  solutions.push_back(solution);
66  this->get_solutions(solutions);
67  return solutions.back();
68  }
69 
70  template<typename Scalar>
72  {
73  if (solutions.size() != this->component_count)
74  throw Exceptions::Exception("Limiter does not have correct number of spaces, solutions.");
75 
76  this->limited_solutions = solutions;
77 
78  // Processing.
79  this->process();
80 
81  if (this->limited_solutions.empty() || this->limited_solutions.size() != this->component_count)
82  throw Exceptions::Exception("Limiter failed for unknown reason.");
83  }
84 
85  template<typename Scalar>
87  {
88  return this->changed_element_ids;
89  }
90 
91  template<typename Scalar>
93  {
94  return true;
95  }
96 
97  template<typename Scalar>
99  {
100  return this->solution_vector;
101  }
102 
103  template<typename Scalar>
104  void Limiter<Scalar>::set_solution_vector(Scalar* solution_vector_)
105  {
106  if (solution_vector_)
107  {
108  try
109  {
110  int ndof = Space<Scalar>::get_num_dofs(this->spaces);
111  Scalar value = solution_vector_[ndof - 1];
112 
113  this->solution_vector = new Scalar[Space<Scalar>::get_num_dofs(this->spaces)];
114  memcpy(this->solution_vector, solution_vector_, sizeof(Scalar)* Space<Scalar>::get_num_dofs(this->spaces));
115  }
116  catch (...)
117  {
118  throw Exceptions::Exception("Wrong combination of space(s) and solution_vector passed to Limiter().");
119  }
120  }
121  }
122 
123  VertexBasedLimiter::VertexBasedLimiter(SpaceSharedPtr<double> space, double* solution_vector, int maximum_polynomial_order)
124  : Limiter<double>(space, solution_vector)
125  {
126  this->init(maximum_polynomial_order);
127  }
128 
129  VertexBasedLimiter::VertexBasedLimiter(std::vector<SpaceSharedPtr<double> > spaces, double* solution_vector, int maximum_polynomial_order)
130  : Limiter<double>(spaces, solution_vector)
131  {
132  this->init(maximum_polynomial_order);
133  }
134 
135  void VertexBasedLimiter::set_p_coarsening_only()
136  {
137  this->p_coarsening_only = true;
138  }
139 
140  void VertexBasedLimiter::init(int maximum_polynomial_order)
141  {
142  this->maximum_polynomial_order = maximum_polynomial_order;
143  this->p_coarsening_only = false;
144 
145  // Checking that this is the Taylor shapeset.
146  for (int i = 0; i < this->component_count; i++)
147  {
148  if (this->spaces[i]->get_shapeset()->get_id() != 31)
149  throw Exceptions::Exception("VertexBasedLimiter designed for L2ShapesetTaylor. Ignore this exception for unforeseen problems.");
150  }
151 
152  vertex_min_values = nullptr;
153  vertex_max_values = nullptr;
154 
155  // This is what is the key aspect of the necessity to use L2ShapesetTaylor (or any other one that uses P_{} also for quads).
156  this->mixed_derivatives_count = (maximum_polynomial_order)*(maximum_polynomial_order + 1) / 2;
157 
158  this->print_details = false;
159  }
160 
161  VertexBasedLimiter::~VertexBasedLimiter()
162  {
163  deallocate_vertex_values();
164  }
165 
166  void VertexBasedLimiter::print_detailed_info(bool print_details_)
167  {
168  this->print_details = print_details_;
169  }
170 
171  std::vector<std::pair<int, double> > VertexBasedLimiter::get_correction_factors() const
172  {
173  return this->correction_factors;
174  }
175 
176  void VertexBasedLimiter::process()
177  {
178  // 0. Preparation.
179  // Start by creating temporary solutions and states for paralelism.
180  Solution<double>::vector_to_solutions(this->solution_vector, this->spaces, this->limited_solutions);
181 
182  // 1. Quadratic
183  // Prepare the vertex values for the quadratic part.
184  prepare_min_max_vertex_values(true);
185 
186  // Use those to incorporate the correction factor.
187  Element* e;
188 
189  // Vector to remember if there was limiting of the second derivatives.
190  std::vector<bool> quadratic_correction_done;
191 
192  if (this->get_verbose_output())
193  std::cout << "Quadratic correction" << std::endl;
194 
195  for (int component = 0; component < this->component_count; component++)
196  {
197  MeshSharedPtr mesh = this->spaces[component]->get_mesh();
198  if (this->get_verbose_output() && this->component_count > 1)
199  std::cout << "Component: " << component << std::endl;
200  for_all_active_elements(e, mesh)
201  {
202  bool second_order = H2D_GET_H_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2 || H2D_GET_V_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2;
203  if (!second_order)
204  {
205  quadratic_correction_done.push_back(false);
206  continue;
207  }
208 
209  if (this->get_verbose_output())
210  std::cout << "Element: " << e->id << std::endl;
211 
212  quadratic_correction_done.push_back(this->impose_quadratic_correction_factor(e, component));
213 
214  if (this->get_verbose_output())
215  std::cout << std::endl;
216  }
217  }
218 
219  // Adjust the solutions according to the quadratic terms handling.
220  Solution<double>::vector_to_solutions(this->solution_vector, this->spaces, this->limited_solutions);
221 
222  // 2. Linear
223  // Prepare the vertex values for the linear part.
224  prepare_min_max_vertex_values(false);
225 
226  if (this->get_verbose_output())
227  std::cout << "Linear correction" << std::endl;
228 
229  int running_i = 0;
230  for (int component = 0; component < this->component_count; component++)
231  {
232  MeshSharedPtr mesh = this->spaces[component]->get_mesh();
233  if (this->get_verbose_output() && this->component_count > 1)
234  std::cout << "Component: " << component << std::endl;
235  for_all_active_elements(e, mesh)
236  {
237  if (this->get_verbose_output())
238  std::cout << "Element: " << e->id << std::endl;
239 
240  bool second_order = H2D_GET_H_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2 || H2D_GET_V_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2;
241  if (quadratic_correction_done[running_i++] || !second_order)
242  this->impose_linear_correction_factor(e, component);
243 
244  if (this->get_verbose_output())
245  std::cout << std::endl;
246  }
247  }
248 
249  // Create the final solutions.
250  Solution<double>::vector_to_solutions(this->solution_vector, this->spaces, this->limited_solutions);
251  }
252 
253  void VertexBasedLimiter::impose_linear_correction_factor(Element* e, int component)
254  {
255  double correction_factor = std::numeric_limits<double>::infinity();
256 
257  double centroid_value_multiplied = this->get_centroid_value_multiplied(e, component, 0);
258  if (this->get_verbose_output())
259  std::cout << std::endl << "center-value: " << centroid_value_multiplied << " (" << 0 << ") ";
260 
261  Solution<double>* sln = dynamic_cast<Solution<double>*>(this->limited_solutions[component].get());
262 
263  for (int i_vertex = 0; i_vertex < e->get_nvert(); i_vertex++)
264  {
265  if (this->get_verbose_output())
266  std::cout << std::endl << "vertex: " << i_vertex;
267 
268  Node* vertex = e->vn[i_vertex];
269  double x, y;
270  RefMap::untransform(e, vertex->x, vertex->y, x, y);
271 
272  double vertex_value = sln->get_ref_value_transformed(e, x, y, 0, 0);
273 
274  if (this->get_verbose_output())
275  std::cout << "\tvalue: " << vertex_value;
276 
277  double fraction;
278  if (std::abs(vertex_value - centroid_value_multiplied) < Hermes::HermesSqrtEpsilon)
279  {
280  fraction = 1.;
281  if (this->get_verbose_output())
282  std::cout << "\tcenter_value";
283  }
284  else
285  if (vertex_value > centroid_value_multiplied)
286  {
287  fraction = std::min(1., (this->vertex_max_values[component][vertex->id][0] - centroid_value_multiplied) / (vertex_value - centroid_value_multiplied));
288  if (this->get_verbose_output())
289  std::cout << "\tmax_value: " << this->vertex_max_values[component][vertex->id][0];
290  }
291  else
292  {
293  fraction = std::min(1., (this->vertex_min_values[component][vertex->id][0] - centroid_value_multiplied) / (vertex_value - centroid_value_multiplied));
294  if (this->get_verbose_output())
295  std::cout << "\tmin_value: " << this->vertex_min_values[component][vertex->id][0];
296  }
297 
298  correction_factor = std::min(correction_factor, fraction);
299  }
300  if (this->get_verbose_output())
301  std::cout << std::endl << "correction_factor " << correction_factor << std::endl;
302 
303  if (correction_factor < (1 - 1e-3))
304  {
305  AsmList<double> al;
306  this->spaces[component]->get_element_assembly_list(e, &al);
307 
308  for (int i_basis_fn = 0; i_basis_fn < al.cnt; i_basis_fn++)
309  {
310  int order = this->spaces[component]->get_shapeset()->get_order(al.idx[i_basis_fn], e->get_mode());
311  if (H2D_GET_H_ORDER(order) == 1 || H2D_GET_V_ORDER(order) == 1)
312  {
313  if (this->p_coarsening_only)
314  this->solution_vector[al.dof[i_basis_fn]] = 0.;
315  else
316  this->solution_vector[al.dof[i_basis_fn]] *= correction_factor;
317  }
318  }
319 
320  this->changed_element_ids.push_back(e->id);
321  this->correction_factors.push_back(std::pair<int, double>(1, correction_factor));
322  }
323  }
324 
325  bool VertexBasedLimiter::impose_quadratic_correction_factor(Element* e, int component)
326  {
327  if (this->get_verbose_output())
328  std::cout << "quadratic: ";
329 
330  double correction_factor = std::numeric_limits<double>::infinity();
331 
332  Solution<double>* sln = dynamic_cast<Solution<double>*>(this->limited_solutions[component].get());
333 
334  for (int i_derivative = 1; i_derivative <= 2; i_derivative++)
335  {
336  double centroid_value_multiplied = this->get_centroid_value_multiplied(e, component, i_derivative);
337  if (this->get_verbose_output())
338  std::cout << std::endl << "center-value: " << centroid_value_multiplied << " (" << i_derivative << ") ";
339 
340  for (int i_vertex = 0; i_vertex < e->get_nvert(); i_vertex++)
341  {
342  if (this->get_verbose_output())
343  std::cout << std::endl << "vertex: " << i_vertex;
344 
345  Node* vertex = e->vn[i_vertex];
346  double x, y;
347  RefMap::untransform(e, vertex->x, vertex->y, x, y);
348 
349  double vertex_value = sln->get_ref_value_transformed(e, x, y, 0, i_derivative);
350 
351  if (this->get_verbose_output())
352  std::cout << "\tvalue: " << vertex_value;
353 
354  double fraction;
355  if (std::abs(vertex_value - centroid_value_multiplied) < Hermes::HermesSqrtEpsilon)
356  {
357  if (this->get_verbose_output())
358  std::cout << "\tcenter_value";
359 
360  fraction = 1.;
361  }
362  else
363  if (vertex_value > centroid_value_multiplied)
364  {
365  fraction = std::min(1., (this->vertex_max_values[component][vertex->id][i_derivative] - centroid_value_multiplied) / (vertex_value - centroid_value_multiplied));
366  if (this->get_verbose_output())
367  std::cout << "\tmax_value: " << this->vertex_max_values[component][vertex->id][i_derivative];
368  }
369  else
370  {
371  fraction = std::min(1., (this->vertex_min_values[component][vertex->id][i_derivative] - centroid_value_multiplied) / (vertex_value - centroid_value_multiplied));
372  if (this->get_verbose_output())
373  std::cout << "\tmin_value: " << this->vertex_min_values[component][vertex->id][i_derivative];
374  }
375 
376  correction_factor = std::min(correction_factor, fraction);
377  }
378  }
379 
380  if (this->get_verbose_output())
381  std::cout << std::endl << "correction_factor " << correction_factor << std::endl;
382 
383  if (correction_factor < (1 - 1e-3))
384  {
385  AsmList<double> al;
386  this->spaces[component]->get_element_assembly_list(e, &al);
387 
388  for (int i_basis_fn = 0; i_basis_fn < al.cnt; i_basis_fn++)
389  {
390  int order = this->spaces[component]->get_shapeset()->get_order(al.idx[i_basis_fn], e->get_mode());
391  if (H2D_GET_H_ORDER(order) == 2 || H2D_GET_V_ORDER(order) == 2)
392  {
393  if (this->p_coarsening_only)
394  this->solution_vector[al.dof[i_basis_fn]] = 0.;
395  else
396  this->solution_vector[al.dof[i_basis_fn]] *= correction_factor;
397  }
398  }
399 
400  this->changed_element_ids.push_back(e->id);
401  this->correction_factors.push_back(std::pair<int, double>(2, correction_factor));
402  return true;
403  }
404  else
405  return false;
406  }
407 
408  void VertexBasedLimiter::prepare_min_max_vertex_values(bool quadratic)
409  {
410  // Reallocate if calculating quadratic part (first of the two).
411  if (quadratic)
412  {
413  deallocate_vertex_values();
414  allocate_vertex_values();
415  }
416 
417  // Calculate min/max vertex values.
418  Element* e;
419  for (int component = 0; component < this->component_count; component++)
420  {
421  MeshSharedPtr mesh = this->spaces[component]->get_mesh();
422 
423  for_all_active_elements(e, mesh)
424  {
425  for (int i_vertex = 0; i_vertex < e->get_nvert(); i_vertex++)
426  {
427  Node* vertex = e->vn[i_vertex];
428  for (int i_derivative = (quadratic ? 1 : 0); i_derivative < (quadratic ? this->mixed_derivatives_count : 1); i_derivative++)
429  {
430  double element_centroid_value_multiplied = this->get_centroid_value_multiplied(e, component, i_derivative);
431  this->vertex_min_values[component][vertex->id][i_derivative] = std::min(this->vertex_min_values[component][vertex->id][i_derivative], element_centroid_value_multiplied);
432  this->vertex_max_values[component][vertex->id][i_derivative] = std::max(this->vertex_max_values[component][vertex->id][i_derivative], element_centroid_value_multiplied);
433  if (e->en[i_vertex]->bnd && this->wider_bounds_on_boundary)
434  {
435  double element_mid_edge_value_multiplied = this->get_edge_midpoint_value_multiplied(e, component, i_derivative, i_vertex);
436 
437  this->vertex_min_values[component][vertex->id][i_derivative] = std::min(this->vertex_min_values[component][vertex->id][i_derivative], element_mid_edge_value_multiplied);
438  this->vertex_max_values[component][vertex->id][i_derivative] = std::max(this->vertex_max_values[component][vertex->id][i_derivative], element_mid_edge_value_multiplied);
439 
440  Node* next_vertex = e->vn[(i_vertex + 1) % e->get_nvert()];
441  this->vertex_min_values[component][next_vertex->id][i_derivative] = std::min(this->vertex_min_values[component][next_vertex->id][i_derivative], element_mid_edge_value_multiplied);
442  this->vertex_max_values[component][next_vertex->id][i_derivative] = std::max(this->vertex_max_values[component][next_vertex->id][i_derivative], element_mid_edge_value_multiplied);
443  }
444  }
445  }
446  }
447  }
448  }
449 
450  double VertexBasedLimiter::get_centroid_value_multiplied(Element* e, int component, int mixed_derivative_index)
451  {
452  if (mixed_derivative_index > 5)
453  {
454  throw Exceptions::MethodNotImplementedException("VertexBasedLimiter::get_centroid_value_multiplied only works for first and second derivatives.");
455  return 0.;
456  }
457 
458  Solution<double>* sln = dynamic_cast<Solution<double>*>(this->limited_solutions[component].get());
459  double result;
460  if (e->get_mode() == HERMES_MODE_TRIANGLE)
461  result = sln->get_ref_value_transformed(e, CENTROID_TRI_X, CENTROID_TRI_Y, 0, mixed_derivative_index);
462  else
463  result = sln->get_ref_value_transformed(e, CENTROID_QUAD_X, CENTROID_QUAD_Y, 0, mixed_derivative_index);
464 
465  return result;
466  }
467 
468  double VertexBasedLimiter::get_edge_midpoint_value_multiplied(Element* e, int component, int mixed_derivative_index, int edge)
469  {
470  if (mixed_derivative_index > 5)
471  {
472  throw Exceptions::MethodNotImplementedException("VertexBasedLimiter::get_centroid_value_multiplied only works for first and second derivatives.");
473  return 0.;
474  }
475 
476  Solution<double>* sln = dynamic_cast<Solution<double>*>(this->limited_solutions[component].get());
477  double result;
478 
479  double x;
480  double y;
481 
482  if (e->get_mode() == HERMES_MODE_TRIANGLE)
483  {
484  if (edge == 0)
485  {
486  x = 0.;
487  y = -1;
488  }
489  else if (edge == 1)
490  {
491  x = 0;
492  y = 0;
493  }
494  else if (edge == 2)
495  {
496  x = -1.;
497  y = 0;
498  }
499  result = sln->get_ref_value_transformed(e, x, y, 0, mixed_derivative_index);
500  }
501  else
502  {
503  if (edge == 0)
504  {
505  x = 0.;
506  y = -1;
507  }
508  else if (edge == 1)
509  {
510  x = 1;
511  y = 0;
512  }
513  else if (edge == 2)
514  {
515  x = 0.;
516  y = 1.;
517  }
518  else if (edge == 3)
519  {
520  x = -1.;
521  y = 0.;
522  }
523  result = sln->get_ref_value_transformed(e, x, y, 0, mixed_derivative_index);
524  }
525 
526  return result;
527  }
528 
529  void VertexBasedLimiter::allocate_vertex_values()
530  {
531  this->vertex_min_values = new double**[this->component_count];
532  for (int i = 0; i < this->component_count; i++)
533  {
534  this->vertex_min_values[i] = new double*[this->spaces[i]->get_mesh()->get_max_node_id()];
535 
536  for (int j = 0; j < this->spaces[i]->get_mesh()->get_max_node_id(); j++)
537  {
538  this->vertex_min_values[i][j] = new double[this->mixed_derivatives_count];
539  for (int k = 0; k < this->mixed_derivatives_count; k++)
540  this->vertex_min_values[i][j][k] = std::numeric_limits<double>::infinity();
541  }
542  }
543 
544  this->vertex_max_values = new double**[this->component_count];
545  for (int i = 0; i < this->component_count; i++)
546  {
547  this->vertex_max_values[i] = new double*[this->spaces[i]->get_mesh()->get_max_node_id()];
548 
549  for (int j = 0; j < this->spaces[i]->get_mesh()->get_max_node_id(); j++)
550  {
551  this->vertex_max_values[i][j] = new double[this->mixed_derivatives_count];
552  for (int k = 0; k < this->mixed_derivatives_count; k++)
553  this->vertex_max_values[i][j][k] = -std::numeric_limits<double>::infinity();
554  }
555  }
556  }
557 
558  void VertexBasedLimiter::deallocate_vertex_values()
559  {
560  if (this->vertex_min_values)
561  {
562  for (int i = 0; i < this->component_count; i++)
563  {
564  for (int j = 0; j < this->spaces[i]->get_mesh()->get_max_node_id(); j++)
565  {
566  delete[] this->vertex_min_values[i][j];
567  delete[] this->vertex_max_values[i][j];
568  }
569 
570  delete[] this->vertex_min_values[i];
571  delete[] this->vertex_max_values[i];
572  }
573 
574  delete[] this->vertex_min_values;
575  delete[] this->vertex_max_values;
576  }
577  }
578 
579  template<typename Scalar>
580  IntegralCalculator<Scalar>::IntegralCalculator(MeshFunctionSharedPtr<Scalar> source_function, int number_of_integrals) : Hermes::Mixins::Loggable(false), number_of_integrals(number_of_integrals)
581  {
582  source_functions.push_back(source_function);
583  }
584 
585  template<typename Scalar>
586  IntegralCalculator<Scalar>::IntegralCalculator(std::vector<MeshFunctionSharedPtr<Scalar> > source_functions, int number_of_integrals) : Hermes::Mixins::Loggable(false), source_functions(source_functions), number_of_integrals(number_of_integrals)
587  {
588  }
589 
590  template<typename Scalar>
592  {
593  std::vector<std::string> markers;
594  markers.push_back(marker);
595  return this->calculate(markers);
596  }
597 
598  template<>
599  void IntegralCalculator<double>::add_results(double* results_local, double* results)
600  {
601  for (int i = 0; i < this->number_of_integrals; i++)
602  {
603 #pragma omp atomic
604  results[i] += results_local[i];
605  }
606  }
607 
608  template<>
609  void IntegralCalculator<std::complex<double> >::add_results(std::complex<double> * results_local, std::complex<double> * results)
610  {
611  for (int i = 0; i < this->number_of_integrals; i++)
612  {
613 #pragma omp critical (integralAddition)
614  results[i] += results_local[i];
615  }
616  }
617 
618  template<typename Scalar>
619  VolumetricIntegralCalculator<Scalar>::VolumetricIntegralCalculator(MeshFunctionSharedPtr<Scalar> source_function, int number_of_integrals) : IntegralCalculator<Scalar>(source_function, number_of_integrals)
620  {
621  }
622 
623  template<typename Scalar>
624  VolumetricIntegralCalculator<Scalar>::VolumetricIntegralCalculator(std::vector<MeshFunctionSharedPtr<Scalar> > source_functions, int number_of_integrals) : IntegralCalculator<Scalar>(source_functions, number_of_integrals)
625  {
626  }
627 
628  template<typename Scalar>
629  Scalar* VolumetricIntegralCalculator<Scalar>::calculate(std::vector<std::string> markers)
630  {
631 #ifdef _DEBUG
632  this->info("User markers");
633  for (unsigned short i = 0; i < markers.size(); i++)
634  this->info("\t%s", markers[i].c_str());
635 #endif
636  // This serves for assembling over the whole domain in the case a passed marker is HERMES_ANY.
637  bool assemble_everywhere = false;
638 
639  std::vector<int> internal_markers;
640  for (unsigned short i = 0; i < markers.size(); i++)
641  {
642  if (markers[i] == HERMES_ANY)
643  {
644  assemble_everywhere = true;
645  break;
646  }
647  else
648  {
649  Hermes::Hermes2D::Mesh::MarkersConversion::IntValid internalMarker = this->source_functions[0]->get_mesh()->get_element_markers_conversion().get_internal_marker(markers[i]);
650  if (internalMarker.valid)
651  internal_markers.push_back(internalMarker.marker);
652  }
653  }
654 
655  Scalar* result = (Scalar*)calloc(this->number_of_integrals, sizeof(Scalar));
656 
657  if (!assemble_everywhere && internal_markers.size() == 0)
658  return result;
659 
660 #ifdef _DEBUG
661  this->info("Internal markers");
662  for (unsigned short i = 0; i < internal_markers.size(); i++)
663  this->info("\t%i", internal_markers[i]);
664 #endif
665 
666  int source_functions_size = this->source_functions.size();
667 
668  Traverse trav(source_functions_size);
669  unsigned int num_states;
670  Traverse::State** states = trav.get_states(this->source_functions, num_states);
671 
672  for (int i = 0; i < source_functions_size; i++)
673  this->source_functions[i]->set_quad_2d(&g_quad_2d_std);
674 
675 #pragma omp parallel num_threads(this->num_threads_used)
676  {
677  RefMap* refmap = new RefMap;
678  refmap->set_quad_2d(&g_quad_2d_std);
679 
680  int thread_number = omp_get_thread_num();
681  int start = (num_states / this->num_threads_used) * thread_number;
682  int end = (num_states / this->num_threads_used) * (thread_number + 1);
683  if (thread_number == this->num_threads_used - 1)
684  end = num_states;
685 
686 #ifdef _DEBUG
687  this->info("Thread %i, states %i - %i", thread_number, start, end);
688 #endif
689  Hermes::Ord* orders = malloc_with_check<Hermes::Ord>(this->number_of_integrals);
690  Func<Hermes::Ord>** func_ord = malloc_with_check<Func<Hermes::Ord>*>(source_functions_size);
691 
692  MeshFunction<Scalar>** source_functions_cloned = malloc_with_check<MeshFunction<Scalar>*>(source_functions_size);
693  for (int i = 0; i < source_functions_size; i++)
694  source_functions_cloned[i] = this->source_functions[i]->clone();
695  Func<Scalar>** func = malloc_with_check<Func<Scalar>*>(source_functions_size);
696 
697  Scalar* result_thread_local = calloc_with_check<Scalar>(this->number_of_integrals);
698  Scalar* result_local = malloc_with_check<Scalar>(this->number_of_integrals);
699  double jacobian_x_weights[H2D_MAX_INTEGRATION_POINTS_COUNT];
700 
701  for (int state_i = start; state_i < end; state_i++)
702  {
703 #ifdef _DEBUG
704  this->info("Thread %i, state %i", thread_number, state_i);
705 #endif
706 
707  Traverse::State* current_state = states[state_i];
708  if (!assemble_everywhere)
709  {
710  bool target_marker = false;
711  for (unsigned short i = 0; i < internal_markers.size(); i++)
712  {
713  if (current_state->rep->marker == internal_markers[i])
714  {
715  target_marker = true;
716  break;
717  }
718  }
719  if (!target_marker)
720  continue;
721  }
722 
723  memset(result_local, 0, sizeof(Scalar)* this->number_of_integrals);
724 
725  // Set active element.
726  for (int i = 0; i < source_functions_size; i++)
727  {
728  if (current_state->e[i])
729  if (current_state->e[i]->used)
730  {
731  source_functions_cloned[i]->set_active_element(current_state->e[i]);
732  source_functions_cloned[i]->set_transform(current_state->sub_idx[i]);
733  }
734  }
735 
736  refmap->set_active_element(current_state->rep);
737 
738  // Integration order.
739  Hermes::Ord order = Hermes::Ord(refmap->get_inv_ref_order());
740  for (int i = 0; i < this->number_of_integrals; i++)
741  orders[i] = Hermes::Ord(0);
742 
743  for (int i = 0; i < source_functions_size; i++)
744  {
745  if (current_state->e[i])
746  {
747  if (current_state->e[i]->used)
748  func_ord[i] = new Func<Ord>(source_functions_cloned[i]->get_fn_order());
749  else
750  func_ord[i] = new Func<Ord>(0);
751  }
752  else
753  func_ord[i] = new Func<Ord>(0);
754  }
755 
756  this->order(func_ord, orders);
757 
758  for (int i = 0; i < this->number_of_integrals; i++)
759  order += orders[i];
760 
761  int order_int = order.get_order();
762  limit_order(order_int, refmap->get_active_element()->get_mode());
763 
764  for (int i = 0; i < source_functions_size; i++)
765  {
766  if (current_state->e[i])
767  {
768  if (current_state->e[i]->used)
769  func[i] = init_fn(source_functions_cloned[i], order_int);
770  else
771  func[i] = init_zero_fn<Scalar>(current_state->rep->get_mode(), order_int);
772  }
773  else
774  func[i] = init_zero_fn<Scalar>(current_state->rep->get_mode(), order_int);
775  }
776 
777  GeomVol<double> geometry;
778  unsigned char n = init_geometry_points_allocated(refmap, order_int, geometry, jacobian_x_weights);
779 
780  this->integral(n, jacobian_x_weights, func, &geometry, result_local);
781 
782  for (unsigned short i = 0; i < source_functions_size; i++)
783  {
784  delete func_ord[i];
785  delete func[i];
786  }
787 
788  for (unsigned short i = 0; i < this->number_of_integrals; i++)
789  result_thread_local[i] += result_local[i];
790  }
791 
792  this->add_results(result_thread_local, result);
793  free_with_check(result_thread_local);
794 
795  for (unsigned short i = 0; i < source_functions_size; i++)
796  delete source_functions_cloned[i];
797  free_with_check(source_functions_cloned);
798  free_with_check(orders);
799  free_with_check(func_ord);
800  free_with_check(func);
801  free_with_check(result_local);
802  delete refmap;
803  }
804 
805  for (int i = 0; i < num_states; i++)
806  delete states[i];
807  free_with_check(states);
808 
809  return result;
810  }
811 
812  template<typename Scalar>
813  SurfaceIntegralCalculator<Scalar>::SurfaceIntegralCalculator(MeshFunctionSharedPtr<Scalar> source_function, int number_of_integrals) : IntegralCalculator<Scalar>(source_function, number_of_integrals)
814  {
815  }
816 
817  template<typename Scalar>
818  SurfaceIntegralCalculator<Scalar>::SurfaceIntegralCalculator(std::vector<MeshFunctionSharedPtr<Scalar> > source_functions, int number_of_integrals) : IntegralCalculator<Scalar>(source_functions, number_of_integrals)
819  {
820  }
821 
822  template<typename Scalar>
823  Scalar* SurfaceIntegralCalculator<Scalar>::calculate(std::vector<std::string> markers)
824  {
825 #ifdef _DEBUG
826  this->info("User markers");
827  for (unsigned short i = 0; i < markers.size(); i++)
828  this->info("\t%s", markers[i].c_str());
829 #endif
830  // This serves for assembling over the whole domain in the case a passed marker is HERMES_ANY.
831  bool assemble_everywhere = false;
832 
833  std::vector<int> internal_markers;
834  for (unsigned short i = 0; i < markers.size(); i++)
835  {
836  if (markers[i] == HERMES_ANY)
837  {
838  assemble_everywhere = true;
839  break;
840  }
841  else
842  {
843  Hermes::Hermes2D::Mesh::MarkersConversion::IntValid internalMarker = this->source_functions[0]->get_mesh()->get_boundary_markers_conversion().get_internal_marker(markers[i]);
844  if (internalMarker.valid)
845  internal_markers.push_back(internalMarker.marker);
846  }
847  }
848 
849  Scalar* result = (Scalar*)calloc(this->number_of_integrals, sizeof(Scalar));
850 
851  if (!assemble_everywhere && internal_markers.size() == 0)
852  return result;
853 
854 #ifdef _DEBUG
855  this->info("Internal markers");
856  for (unsigned short i = 0; i < internal_markers.size(); i++)
857  this->info("\t%i", internal_markers[i]);
858 #endif
859 
860  int source_functions_size = this->source_functions.size();
861  Traverse trav(source_functions_size);
862  unsigned int num_states;
863  Traverse::State** states = trav.get_states(this->source_functions, num_states);
864 
865  for (int i = 0; i < source_functions_size; i++)
866  this->source_functions[i]->set_quad_2d(&g_quad_2d_std);
867 
868 #pragma omp parallel num_threads(this->num_threads_used)
869  {
870  RefMap* refmap = new RefMap;
871  refmap->set_quad_2d(&g_quad_2d_std);
872 
873  int thread_number = omp_get_thread_num();
874  int start = (num_states / this->num_threads_used) * thread_number;
875  int end = (num_states / this->num_threads_used) * (thread_number + 1);
876  if (thread_number == this->num_threads_used - 1)
877  end = num_states;
878 
879 #ifdef _DEBUG
880  this->info("Thread %i, states %i - %i", thread_number, start, end);
881 #endif
882 
883  Hermes::Ord* orders = malloc_with_check<Hermes::Ord>(this->number_of_integrals);
884  Func<Hermes::Ord>** func_ord = malloc_with_check<Func<Hermes::Ord>*>(source_functions_size);
885 
886  MeshFunction<Scalar>** source_functions_cloned = malloc_with_check<MeshFunction<Scalar>*>(source_functions_size);
887  for (int i = 0; i < source_functions_size; i++)
888  source_functions_cloned[i] = this->source_functions[i]->clone();
889  Func<Scalar>** func = malloc_with_check<Func<Scalar>*>(source_functions_size);
890 
891  Scalar* result_thread_local = calloc_with_check<Scalar>(this->number_of_integrals);
892  Scalar* result_local = malloc_with_check<Scalar>(this->number_of_integrals);
893  double jacobian_x_weights[H2D_MAX_INTEGRATION_POINTS_COUNT];
894 
895  for (int state_i = start; state_i < end; state_i++)
896  {
897 #ifdef _DEBUG
898  this->info("Thread %i, state %i", thread_number, state_i);
899 #endif
900 
901  Traverse::State* current_state = states[state_i];
902 
903  // Set active element.
904  for (unsigned short i = 0; i < source_functions_size; i++)
905  {
906  if (current_state->e[i])
907  if (current_state->e[i]->used)
908  {
909  source_functions_cloned[i]->set_active_element(current_state->e[i]);
910  source_functions_cloned[i]->set_transform(current_state->sub_idx[i]);
911  }
912  }
913 
914  refmap->set_active_element(current_state->rep);
915 
916  Hermes::Ord order = Hermes::Ord(refmap->get_inv_ref_order());
917 
918  for (unsigned short edge = 0; edge < current_state->rep->nvert; edge++)
919  {
920 #ifdef _DEBUG
921  this->info("Thread %i, state %i, edge %i", thread_number, state_i, edge);
922 #endif
923  if (!assemble_everywhere)
924  {
925  bool target_marker = false;
926  for (unsigned short i = 0; i < internal_markers.size(); i++)
927  {
928  if (current_state->rep->en[edge]->marker == internal_markers[i])
929  {
930  target_marker = true;
931  break;
932  }
933  }
934  if (!target_marker)
935  continue;
936  }
937 
938  memset(result_local, 0, sizeof(Scalar)* this->number_of_integrals);
939 
940  // Integration order.
941  for (int i = 0; i < this->number_of_integrals; i++)
942  orders[i] = Hermes::Ord(0);
943  for (int i = 0; i < source_functions_size; i++)
944  func_ord[i] = new Func<Ord>(source_functions_cloned[i]->get_fn_order());
945 
946  this->order(func_ord, orders);
947 
948  for (int i = 0; i < this->number_of_integrals; i++)
949  order += orders[i];
950 
951  int order_int = order.get_order();
952  limit_order(order_int, refmap->get_active_element()->get_mode());
953 
954  GeomSurf<double> geometry;
955  int n = init_surface_geometry_points_allocated(refmap, order_int, edge, current_state->rep->en[edge]->marker, geometry, jacobian_x_weights);
956 
957  for (int i = 0; i < source_functions_size; i++)
958  {
959  if (current_state->e[i])
960  {
961  if (current_state->e[i]->used)
962  func[i] = init_fn(source_functions_cloned[i], order_int);
963  else
964  func[i] = init_zero_fn<Scalar>(current_state->rep->get_mode(), order_int);
965  }
966  else
967  func[i] = init_zero_fn<Scalar>(current_state->rep->get_mode(), order_int);
968  }
969 
970  this->integral(n, jacobian_x_weights, func, &geometry, result_local);
971 
972  for (int i = 0; i < source_functions_size; i++)
973  {
974  delete func_ord[i];
975  delete func[i];
976  }
977 
978  for (int i = 0; i < this->number_of_integrals; i++)
979  result_thread_local[i] += .5 * result_local[i];
980  }
981  }
982 
983  this->add_results(result_thread_local, result);
984  free_with_check(result_thread_local);
985 
986  for (int i = 0; i < source_functions_size; i++)
987  delete source_functions_cloned[i];
988  free_with_check(source_functions_cloned);
989  free_with_check(orders);
990  free_with_check(func_ord);
991  free_with_check(func);
992  free_with_check(result_local);
993  delete refmap;
994  }
995 
996  for (int i = 0; i < num_states; i++)
997  delete states[i];
998  free_with_check(states);
999 
1000  return result;
1001  }
1002 
1003  template class HERMES_API Limiter < double > ;
1004  template class HERMES_API VolumetricIntegralCalculator < double > ;
1005  template class HERMES_API SurfaceIntegralCalculator < double > ;
1006  template class HERMES_API Limiter < std::complex<double> > ;
1007  template class HERMES_API VolumetricIntegralCalculator < std::complex<double> > ;
1008  template class HERMES_API SurfaceIntegralCalculator < std::complex<double> > ;
1009  }
1010  }
1011 }
Element * get_active_element() const
Definition: transformable.h:48
Definition: adapt.h:24
int marker
element marker
Definition: element.h:144
Scalar * calculate(std::vector< std::string > markers)
#define CENTROID_QUAD_X
Centroid of the reference quadrilateral.
Definition: global.h:47
Represents a function defined on a mesh.
Definition: mesh_function.h:56
Used to pass the instances of Space around.
Definition: space.h:34
bool used
array item usage flag
Definition: element.h:116
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
unsigned char nvert
number of vertices (3 or 4)
Definition: element.h:222
Scalar * calculate(std::vector< std::string > markers)
int get_num_dofs() const
Returns the number of basis functions contained in the space.
Definition: space.cpp:286
int get_inv_ref_order() const
Returns the increase in the integration order due to the reference map.
Definition: refmap.h:101
static void vector_to_solutions(const Scalar *solution_vector, std::vector< SpaceSharedPtr< Scalar > > spaces, std::vector< MeshFunctionSharedPtr< Scalar > > solutions, std::vector< bool > add_dir_lift=std::vector< bool >(), std::vector< int > start_indices=std::vector< int >())
Passes solution components calculated from solution vector as Solutions.
Definition: solution.cpp:443
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
static void untransform(Element *e, double x, double y, double &xi1, double &xi2)
Definition: refmap.cpp:542
Struct for return type of get_internal_marker().
Definition: mesh.h:251
void set_quad_2d(Quad2D *quad_2d)
Definition: refmap.cpp:63
::xsd::cxx::tree::string< char, simple_type > string
C++ type corresponding to the string XML Schema built-in type.
Represents a finite element space over a domain.
Definition: api2d.h:34
Represents the reference mapping.
Definition: refmap.h:40
State ** get_states(std::vector< MeshSharedPtr > meshes, unsigned int &states_count)
Definition: traverse.cpp:292
#define CENTROID_TRI_X
Centroid of the reference triangle.
Definition: global.h:50
int marker
edge marker
Definition: element.h:68
IntegralCalculator(MeshFunctionSharedPtr< Scalar > source_function, int number_of_integrals)
virtual Scalar * calculate(std::vector< std::string > markers)=0
Represents the solution of a PDE.
Definition: api2d.h:35
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)
virtual void set_active_element(Element *e)
Definition: refmap.cpp:70