Hermes2D  3.0
error_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_calculator.h"
17 #include "function/exact_solution.h"
18 #include "adapt/error_thread_calculator.h"
19 #include "norm_form.h"
20 
21 namespace Hermes
22 {
23  namespace Hermes2D
24  {
25  template<typename Scalar>
27  errorType(errorType),
28  elements_stored(false),
29  element_references(nullptr),
30  errors_squared_sum(0.0),
31  norms_squared_sum(0.0)
32  {
33  memset(errors, 0, sizeof(double*)* H2D_MAX_COMPONENTS);
34  memset(norms, 0, sizeof(double*)* H2D_MAX_COMPONENTS);
35  }
36 
37  template<typename Scalar>
39  {
40  this->free();
41  }
42 
43  template<typename Scalar>
45  {
46  if (component >= this->component_count)
47  throw Exceptions::ValueException("component", component, this->component_count);
48 
49  // The value is ready to be returned if it has been initialized and no other error calculation has been
50  // performed since.
51  if (this->errorMeshFunction[component])
52  return this->errorMeshFunction[component];
53  else
54  {
55  this->errorMeshFunction[component].reset(new ExactSolutionConstantArray<double, double>(coarse_solutions[component]->get_mesh(), this->errors[component]));
56  return this->errorMeshFunction[component];
57  }
58  }
59 
60  template<typename Scalar>
62  {
63  this->num_act_elems = 0;
64  errors_squared_sum = 0.;
65  norms_squared_sum = 0.;
66 
67  // For all components, get the number of active elements,
68  // make room for elements, optionally for norms, and incerementaly
69  // calculate the total number of elements.
70  for (int i = 0; i < this->component_count; i++)
71  {
72  int num_elements_i = this->coarse_solutions[i]->get_mesh()->get_max_element_id();
73 
74  this->errors[i] = realloc_with_check<ErrorCalculator<Scalar>, double>(errors[i], num_elements_i, this);
75  memset(this->errors[i], 0, sizeof(double)* num_elements_i);
76 
77  this->norms[i] = realloc_with_check<ErrorCalculator<Scalar>, double>(norms[i], num_elements_i, this);
78  memset(this->norms[i], 0, sizeof(double)* num_elements_i);
79 
80  component_errors[i] = 0.;
81  component_norms[i] = 0.;
82  int num_active_elements_i = this->coarse_solutions[i]->get_mesh()->get_num_active_elements();
83  element_count[i] = num_active_elements_i;
84  this->num_act_elems += num_active_elements_i;
85  }
86 
87  // (Re-)create the array for references and initialize it.
88  free_with_check(this->element_references);
89  this->element_references = malloc_with_check<ErrorCalculator<Scalar>, ElementReference>(this->num_act_elems, this);
90 
91  int running_count_total = 0;
92  for (int i = 0; i < this->component_count; i++)
93  {
94  Element* e;
95  for_all_active_elements(e, this->coarse_solutions[i]->get_mesh())
96  {
97  this->element_references[running_count_total++] = ErrorCalculator<Scalar>::ElementReference(i, e->id, &this->errors[i][e->id], &this->norms[i][e->id]);
98  }
99  }
100 
101  // Also handle the errorMeshFunction.
102  for (int i = 0; i < this->component_count; i++)
103  if (this->errorMeshFunction[i])
104  this->errorMeshFunction[i].reset();
105  }
106 
107  template<typename Scalar>
109  {
110  for (int i = 0; i < this->component_count; i++)
111  {
112  free_with_check(errors[i], true);
113  free_with_check(norms[i], true);
114  }
115 
116  free_with_check(this->element_references);
117  }
118 
119  template<typename Scalar>
121  {
122  std::vector<MeshFunctionSharedPtr<Scalar> > coarse_solutions;
123  coarse_solutions.push_back(coarse_solution);
124  std::vector<MeshFunctionSharedPtr<Scalar> > fine_solutions;
125  fine_solutions.push_back(fine_solution);
126  this->calculate_errors(coarse_solutions, fine_solutions, sort_and_store);
127  }
128 
129  template<typename Scalar>
131  {
132  bool okay = true;
133 
134  try
135  {
136  Helpers::check_length(this->fine_solutions, this->component_count);
137  }
138  catch (...)
139  {
140  okay = false;
141  throw;
142  }
143 
144  if (this->mfvol.empty() && this->mfsurf.empty() && this->mfDG.empty())
145  {
146  okay = false;
147  throw Exceptions::Exception("No error forms - instances of NormForm<Scalar> passed to ErrorCalculator via add_error_form().");
148  }
149 
150  return okay;
151  }
152 
153  template<typename Scalar>
154  void ErrorCalculator<Scalar>::calculate_errors(std::vector<MeshFunctionSharedPtr<Scalar> > coarse_solutions_, std::vector<MeshFunctionSharedPtr<Scalar> > fine_solutions_, bool sort_and_store)
155  {
156  this->coarse_solutions = coarse_solutions_;
157  this->fine_solutions = fine_solutions_;
158  this->component_count = this->coarse_solutions.size();
159 
160  this->check();
161 
162  this->init_data_storage();
163 
164  // Prepare multi-mesh traversal and error arrays.
165  std::vector<MeshSharedPtr> meshes;
166 
167  for (int i = 0; i < this->component_count; i++)
168  meshes.push_back(coarse_solutions[i]->get_mesh());
169  for (int i = 0; i < this->component_count; i++)
170  meshes.push_back(fine_solutions[i]->get_mesh());
171 
172  unsigned int num_states;
173  Traverse trav(this->component_count);
174  Traverse::State** states = trav.get_states(meshes, num_states);
175 
176 #pragma omp parallel num_threads(this->num_threads_used)
177  {
178  int thread_number = omp_get_thread_num();
179  int start = (num_states / this->num_threads_used) * thread_number;
180  int end = (num_states / this->num_threads_used) * (thread_number + 1);
181  if (thread_number == this->num_threads_used - 1)
182  end = num_states;
183 
184  try
185  {
186  // Create a calculator for this thread.
187  ErrorThreadCalculator<Scalar> errorThreadCalculator(this);
188 
189  // Do the work.
190  for (int state_i = start; state_i < end; state_i++)
191  errorThreadCalculator.evaluate_one_state(states[state_i]);
192  }
193  catch (Hermes::Exceptions::Exception& e)
194  {
195 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
196  this->exceptionMessageCaughtInParallelBlock = e.info();
197  }
198  catch (std::exception& e)
199  {
200 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
201  this->exceptionMessageCaughtInParallelBlock = e.what();
202  }
203  }
204 
205  for (int i = 0; i < num_states; i++)
206  delete states[i];
207  free_with_check(states);
208 
209  // Clean after ourselves.
210  for (int i = 0; i < this->component_count; i++)
211  {
212  Element* e;
213  for_all_active_elements(e, coarse_solutions[i]->get_mesh())
214  e->visited = false;
215  for_all_active_elements(e, fine_solutions[i]->get_mesh())
216  e->visited = false;
217  }
218 
219  if (!this->exceptionMessageCaughtInParallelBlock.empty())
220  throw Hermes::Exceptions::Exception(this->exceptionMessageCaughtInParallelBlock.c_str());
221 
222  // Sums calculation & error postprocessing.
223  this->postprocess_error();
224 
225  if (sort_and_store)
226  {
227  std::qsort(this->element_references, this->num_act_elems, sizeof(ElementReference), &this->compareElementReference);
228  elements_stored = true;
229  }
230  else
231  elements_stored = false;
232  }
233 
234  template<typename Scalar>
236  {
237  // Indexer through active elements on all meshes.
238  int running_indexer = 0;
239  for (int i = 0; i < this->component_count; i++)
240  {
241  for (int j = 0; j < this->element_count[i]; j++)
242  {
243  component_errors[i] += *(this->element_references[running_indexer + j].error);
244  component_norms[i] += *(this->element_references[running_indexer + j].norm);
245 
246  if (this->errorType == RelativeErrorToElementNorm)
247  *(this->element_references[running_indexer + j].error) /= *(this->element_references[running_indexer + j].norm);
248  }
249 
250  if (this->errorType == RelativeErrorToGlobalNorm)
251  for (int j = 0; j < this->element_count[i]; j++)
252  {
253  if (component_norms[i] < Hermes::HermesEpsilon)
254  *(this->element_references[running_indexer + j].error) = 0.;
255  else
256  *(this->element_references[running_indexer + j].error) /= component_norms[i];
257  }
258 
259  norms_squared_sum += component_norms[i];
260  errors_squared_sum += component_errors[i];
261 
262  if (this->errorType == RelativeErrorToGlobalNorm || this->errorType == RelativeErrorToElementNorm)
263  {
264  if (component_norms[i] < Hermes::HermesEpsilon)
265  component_errors[i] = 0.;
266  else
267  component_errors[i] /= component_norms[i];
268  }
269 
270  running_indexer += this->element_count[i];
271  }
272 
273  if (this->errorType == RelativeErrorToGlobalNorm || this->errorType == RelativeErrorToElementNorm)
274  {
275  if (norms_squared_sum < Hermes::HermesEpsilon)
276  errors_squared_sum = 0.;
277  else
278  errors_squared_sum /= norms_squared_sum;
279  }
280  }
281 
282  template<typename Scalar>
284  {
285  this->mfvol.push_back(form);
286  }
287 
288  template<typename Scalar>
290  {
291  this->mfsurf.push_back(form);
292  }
293 
294  template<typename Scalar>
295  void ErrorCalculator<Scalar>::add_error_form(NormFormDG<Scalar>* form)
296  {
297  this->mfDG.push_back(form);
298  }
299 
300  template<typename Scalar>
302  {
303  if (!this->element_references)
304  {
305  throw Hermes::Exceptions::Exception("Elements / norms have not been calculated so far.");
306  return false;
307  }
308 
309  return true;
310  }
311 
312  template<typename Scalar>
314  {
315  return this->element_references[id];
316  }
317 
318  template<typename Scalar>
319  double ErrorCalculator<Scalar>::get_element_error_squared(int component, int element_id) const
320  {
321  if (!this->data_prepared_for_querying())
322  return 0.0;
323 
324  if (component >= this->component_count)
325  throw Hermes::Exceptions::ValueException("component", component, this->component_count);
326 
327  return this->errors[component][element_id];
328  }
329 
330  template<typename Scalar>
331  double ErrorCalculator<Scalar>::get_element_norm_squared(int component, int element_id) const
332  {
333  if (!this->data_prepared_for_querying())
334  return 0.0;
335  if (component >= this->component_count)
336  throw Hermes::Exceptions::ValueException("component", component, this->component_count);
337 
338  return this->norms[component][element_id];
339  }
340 
341  template<typename Scalar>
342  double ErrorCalculator<Scalar>::get_error_squared(int component) const
343  {
344  if (!this->data_prepared_for_querying())
345  return 0.0;
346  if (component >= this->component_count)
347  throw Hermes::Exceptions::ValueException("component", component, this->component_count);
348 
349  return this->component_errors[component];
350  }
351 
352  template<typename Scalar>
353  double ErrorCalculator<Scalar>::get_norm_squared(int component) const
354  {
355  if (!this->data_prepared_for_querying())
356  return 0.0;
357  if (component >= this->component_count)
358  throw Hermes::Exceptions::ValueException("component", component, this->component_count);
359 
360  return this->component_norms[component];
361  }
362 
363  template<typename Scalar>
364  double ErrorCalculator<Scalar>::get_total_error_squared() const
365  {
366  if (!this->data_prepared_for_querying())
367  return 0.0;
368  return this->errors_squared_sum;
369  }
370 
371  template<typename Scalar>
372  double ErrorCalculator<Scalar>::get_total_norm_squared() const
373  {
374  if (!this->data_prepared_for_querying())
375  return 0.0;
376  return this->norms_squared_sum;
377  }
378 
379  template<typename Scalar, NormType normType>
380  DefaultErrorCalculator<Scalar, normType>::DefaultErrorCalculator(CalculatedErrorType errorType, int component_count) : ErrorCalculator<Scalar>(errorType)
381  {
382  for (int i = 0; i < component_count; i++)
383  {
384  this->add_error_form(new DefaultNormFormVol<Scalar>(i, i, normType));
385  }
386  }
387 
388  template<typename Scalar, NormType normType>
389  DefaultNormCalculator<Scalar, normType>::DefaultNormCalculator(int component_count) : ErrorCalculator<Scalar>(AbsoluteError)
390  {
391  for (int i = 0; i < component_count; i++)
392  {
393  this->add_error_form(new DefaultNormFormVol<Scalar>(i, i, normType));
394  }
395  }
396 
397  template<typename Scalar, NormType normType>
399  {
400  std::vector<MeshFunctionSharedPtr<Scalar> > zero_fine_solutions;
401  for (unsigned short i = 0; i < solutions.size(); i++)
402  zero_fine_solutions.push_back(MeshFunctionSharedPtr<Scalar>(new ZeroSolution<Scalar>(solutions[i]->get_mesh())));
403  this->calculate_errors(solutions, zero_fine_solutions, false);
404 
405  return this->get_total_error_squared();
406  }
407 
408  template<typename Scalar, NormType normType>
410  {
411  MeshFunctionSharedPtr<Scalar> zero_fine_solution(new ZeroSolution<Scalar>(solution->get_mesh()));
412  this->calculate_errors(solution, zero_fine_solution, false);
413 
414  return this->get_total_error_squared();
415  }
416 
417  template<typename Scalar, NormType normType>
419  {
420  for (unsigned short i = 0; i < this->mfvol.size(); i++)
421  delete this->mfvol[i];
422  }
423 
424  template<typename Scalar, NormType normType>
425  DefaultNormCalculator<Scalar, normType>::~DefaultNormCalculator()
426  {
427  for (unsigned short i = 0; i < this->mfvol.size(); i++)
428  delete this->mfvol[i];
429  }
430 
431  template HERMES_API class DefaultErrorCalculator < double, HERMES_H1_NORM > ;
432  template HERMES_API class DefaultErrorCalculator < std::complex<double>, HERMES_H1_NORM > ;
433  template HERMES_API class DefaultErrorCalculator < double, HERMES_L2_NORM > ;
434  template HERMES_API class DefaultErrorCalculator < std::complex<double>, HERMES_L2_NORM > ;
435  template HERMES_API class DefaultErrorCalculator < double, HERMES_H1_SEMINORM > ;
436  template HERMES_API class DefaultErrorCalculator < std::complex<double>, HERMES_H1_SEMINORM > ;
437  template HERMES_API class DefaultErrorCalculator < double, HERMES_HCURL_NORM > ;
438  template HERMES_API class DefaultErrorCalculator < std::complex<double>, HERMES_HCURL_NORM > ;
439  template HERMES_API class DefaultErrorCalculator < double, HERMES_HDIV_NORM > ;
440  template HERMES_API class DefaultErrorCalculator < std::complex<double>, HERMES_HDIV_NORM > ;
441 
442  template HERMES_API class DefaultNormCalculator < double, HERMES_H1_NORM > ;
443  template HERMES_API class DefaultNormCalculator < std::complex<double>, HERMES_H1_NORM > ;
444  template HERMES_API class DefaultNormCalculator < double, HERMES_L2_NORM > ;
445  template HERMES_API class DefaultNormCalculator < std::complex<double>, HERMES_L2_NORM > ;
446  template HERMES_API class DefaultNormCalculator < double, HERMES_H1_SEMINORM > ;
447  template HERMES_API class DefaultNormCalculator < std::complex<double>, HERMES_H1_SEMINORM > ;
448  template HERMES_API class DefaultNormCalculator < double, HERMES_HCURL_NORM > ;
449  template HERMES_API class DefaultNormCalculator < std::complex<double>, HERMES_HCURL_NORM > ;
450  template HERMES_API class DefaultNormCalculator < double, HERMES_HDIV_NORM > ;
451  template HERMES_API class DefaultNormCalculator < std::complex<double>, HERMES_HDIV_NORM > ;
452 
453  template HERMES_API class ErrorCalculator < double > ;
454  template HERMES_API class ErrorCalculator < std::complex<double> > ;
455  }
456 }
::xsd::cxx::tree::id< char, ncname > id
C++ type corresponding to the ID XML Schema built-in type.
Definition: adapt.h:24
int id
element id number
Definition: element.h:112
ErrorCalculator(CalculatedErrorType errorType)
Stores one element of a mesh.
Definition: element.h:107
Containc class that calculates the norm.
bool visited
true if the element has been visited during assembling
Definition: element.h:120
bool data_prepared_for_querying() const
Common check for data querying.
void add_error_form(NormFormVol< Scalar > *form)
void calculate_errors(std::vector< MeshFunctionSharedPtr< Scalar > > coarse_solutions, std::vector< MeshFunctionSharedPtr< Scalar > > fine_solutions, bool sort_and_store=true)
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
double * errors[H2D_MAX_COMPONENTS]
Errors of elements. Meaning of the error depeds on the errorType.
double calculate_norm(MeshFunctionSharedPtr< Scalar > solution)
Norms calculation.
double calculate_norms(std::vector< MeshFunctionSharedPtr< Scalar > > &solutions)
Norms calculation.
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_...
double get_element_error_squared(int component, int element_id) const
Returns a squared error of an element.
int component_count
Number of solution components.
CalculatedErrorType
Enum passed to the class ErrorCalculator specifying the calculated errors.
Evaluation of an error between a (coarse) solution and a reference solution.
Definition: adapt.h:28
MeshFunctionSharedPtr< double > get_errorMeshFunction(int component=0)
State ** get_states(std::vector< MeshSharedPtr > meshes, unsigned int &states_count)
Definition: traverse.cpp:292
void init_data_storage()
Initialize the data storage.
virtual ~ErrorCalculator()
Destructor. Deallocates allocated private data.
virtual bool isOkay() const
State querying helpers.