Hermes2D  3.0
adapt_solver.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_solver.h"
17 #include "solver/linear_solver.h"
18 #include "solver/newton_solver.h"
19 #include "solver/picard_solver.h"
20 #include "ogprojection.h"
21 #include "views/scalar_view.h"
22 #include "views/base_view.h"
23 #include "views/order_view.h"
24 #include "views/mesh_view.h"
25 
26 namespace Hermes
27 {
28  namespace Hermes2D
29  {
30  AdaptSolverCriterion::AdaptSolverCriterion()
31  {
32  }
33 
34  AdaptSolverCriterionErrorThreshold::AdaptSolverCriterionErrorThreshold(double error_tolerance) : AdaptSolverCriterion(), error_threshold(error_threshold)
35  {
36  }
37 
38  bool AdaptSolverCriterionErrorThreshold::done(double error, unsigned short iteration)
39  {
40  return error < this->error_threshold;
41  }
42 
43  AdaptSolverCriterionFixed::AdaptSolverCriterionFixed(unsigned short refinement_levels) : AdaptSolverCriterion(), refinement_levels(refinement_levels)
44  {
45  }
46 
47  bool AdaptSolverCriterionFixed::done(double error, unsigned short iteration)
48  {
49  return iteration >= this->refinement_levels;
50  }
51 
52  template<typename Scalar, typename SolverType>
53  AdaptSolver<Scalar, SolverType>::AdaptSolver(std::vector<SpaceSharedPtr<Scalar> > initial_spaces, WeakFormSharedPtr<Scalar> wf, ErrorCalculator<Scalar>* error_calculator, AdaptivityStoppingCriterion<Scalar>* stopping_criterion_single_step, std::vector<RefinementSelectors::Selector<Scalar>*> selectors, AdaptSolverCriterion* stopping_criterion_global)
54  : spaces(initial_spaces), wf(wf), error_calculator(error_calculator), stopping_criterion_single_step(stopping_criterion_single_step), selectors(selectors), stopping_criterion_global(stopping_criterion_global)
55  {
56  this->init();
57  }
58 
59  template<typename Scalar, typename SolverType>
61  : wf(wf), stopping_criterion_single_step(stopping_criterion_single_step), error_calculator(error_calculator), stopping_criterion_global(stopping_criterion_global)
62  {
63  this->spaces.push_back(initial_space);
64  this->selectors.push_back(selector);
65 
66  this->init();
67  }
68 
69  template<typename Scalar, typename SolverType>
71  {
72  this->number_of_equations = this->spaces.size();
73  Helpers::check_length(this->selectors, this->number_of_equations);
74  this->solve_method_running = false;
75  this->visualization = false;
76  this->wait_for_keypress = false;
77  this->prev_mat = nullptr;
78  this->prev_rhs = nullptr;
79  this->prev_dirichlet_lift_rhs = nullptr;
80  this->solver = new SolverType(wf, spaces);
81  }
82 
83  template<typename Scalar, typename SolverType>
85  {
86  if (this->prev_mat)
87  delete this->prev_mat;
88 
89  if (this->prev_rhs)
90  delete this->prev_rhs;
91 
92  if (this->prev_dirichlet_lift_rhs)
93  delete this->prev_dirichlet_lift_rhs;
94 
95  delete this->solver;
96  }
97 
98  template<typename Scalar, typename SolverType>
100  {
101  Loggable::set_verbose_output(to_set);
102  if (this->error_calculator)
103  this->error_calculator->set_verbose_output(to_set);
104  }
105 
106  template<typename Scalar, typename SolverType>
107  void AdaptSolver<Scalar, SolverType>::switch_visualization(bool on_off, bool wait_for_keypress_on_off)
108  {
109  this->visualization = on_off;
110  this->wait_for_keypress = wait_for_keypress_on_off;
111  }
112 
113  template<typename Scalar>
115  {
116  public:
117  static int current_iteration;
118  static std::unordered_set<unsigned int>* current_elements_to_reassemble[H2D_MAX_COMPONENTS];
119  static std::unordered_set<int>* current_DOFs_to_reassemble[H2D_MAX_COMPONENTS];
120  static std::vector<SpaceSharedPtr<Scalar> >* current_ref_spaces;
121  static std::vector<SpaceSharedPtr<Scalar> >* current_prev_ref_spaces;
122  static unsigned char current_number_of_equations;
123  static CSCMatrix<Scalar>* current_prev_mat;
124  static Vector<Scalar>* current_prev_rhs;
125  static Vector<Scalar>* current_prev_dirichlet_lift_rhs;
126 
127  static bool use_Dirichlet;
128  static bool** reusable_DOFs;
129  static bool** reusable_Dirichlet;
130  };
131 
132  template<typename Scalar>
134 
135  template<typename Scalar>
136  std::unordered_set<unsigned int>* StateReassemblyHelper<Scalar>::current_elements_to_reassemble[H2D_MAX_COMPONENTS];
137 
138  template<typename Scalar>
139  std::unordered_set<int>* StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[H2D_MAX_COMPONENTS];
140 
141  template<typename Scalar>
142  std::vector<SpaceSharedPtr<Scalar> >* StateReassemblyHelper<Scalar>::current_ref_spaces;
143 
144  template<typename Scalar>
145  std::vector<SpaceSharedPtr<Scalar> >* StateReassemblyHelper<Scalar>::current_prev_ref_spaces;
146 
147  template<typename Scalar>
149 
150  template<typename Scalar>
152 
153  template<typename Scalar>
155 
156  template<typename Scalar>
158 
159  template<typename Scalar>
161 
162  template<typename Scalar>
164 
165  template<typename Scalar>
167 
168  //#define DEBUG_VIEWS
169 
170  template<typename Scalar>
171  static bool compare(Scalar a, Scalar b);
172 
173  template<>
174  bool compare(std::complex<double> a, std::complex<double> b)
175  {
176  if (a.real() < b.real() && a.imag() < b.imag())
177  return true;
178  else
179  return false;
180  }
181 
182  template<>
183  bool compare(double a, double b)
184  {
185  return a < b;
186  }
187 
188  template<typename Scalar>
189  void get_states_to_reassemble(Traverse::State**& states, unsigned int& num_states, SparseMatrix<Scalar>* mat, Vector<Scalar>* rhs, Vector<Scalar>* dirichlet_lift_rhs, Scalar*& coeff_vec)
190  {
191  int current_iteration = StateReassemblyHelper<Scalar>::current_iteration;
192  if (StateReassemblyHelper<Scalar>::current_iteration == 1)
193  {
194  (*StateReassemblyHelper<Scalar>::reusable_DOFs) = nullptr;
195  (*StateReassemblyHelper<Scalar>::reusable_Dirichlet) = nullptr;
196  return;
197  }
198 
199  // Create utility data
200  // - time measurement
201  Hermes::Mixins::TimeMeasurable cpu_time;
202  // - size of spaces
203  // - shortcuts for spaces, to speed up indirect accesses
204  Space<Scalar>** prev_ref_spaces = new Space<Scalar>*[StateReassemblyHelper<Scalar>::current_number_of_equations];
205  Space<Scalar>** ref_spaces = new Space<Scalar>*[StateReassemblyHelper<Scalar>::current_number_of_equations];
206  // - number of elements of all new reference spaces combined
207  int total_elements_new_spaces = 0;
208  // - fill the above structures
209  for (unsigned short i = 0; i < StateReassemblyHelper<Scalar>::current_number_of_equations; i++)
210  {
211  prev_ref_spaces[i] = StateReassemblyHelper<Scalar>::current_prev_ref_spaces->at(i).get();
212  ref_spaces[i] = StateReassemblyHelper<Scalar>::current_ref_spaces->at(i).get();
213  total_elements_new_spaces += ref_spaces[i]->get_mesh()->get_num_active_elements();
214  }
215  // - elements to reassemble on the new space
216  // -- we could maybe directly used the resulting states (in which we are interested), but it would be complicated.
217  std::unordered_set<unsigned int> newSpace_elements_to_reassemble[H2D_MAX_COMPONENTS];
218  // - number of DOFs of the previous spaces.
219  unsigned int prev_ref_system_size = StateReassemblyHelper<Scalar>::current_prev_mat->get_size();
220  unsigned int ref_system_size = Space<Scalar>::get_num_dofs(*StateReassemblyHelper<Scalar>::current_ref_spaces);
221  // - DOF to DOF map of those DOFs we can reuse. -1s are there to distinguish those we cannot.
222  int* DOF_to_DOF_map = malloc_with_check<int>(prev_ref_system_size);
223  for (unsigned int i = 0; i < prev_ref_system_size; i++)
224  DOF_to_DOF_map[i] = -1;
225  // - DOF to reassemble.
226  (*StateReassemblyHelper<Scalar>::reusable_DOFs) = calloc_with_check<bool>(ref_system_size);
227  (*StateReassemblyHelper<Scalar>::reusable_Dirichlet) = calloc_with_check<bool>(StateReassemblyHelper<Scalar>::current_number_of_equations);
228  // - utility assembly lists.
229  AsmList<Scalar> al, al_prev;
230  // - dummy functions for traversing the previous and current reference spaces together
231  std::vector<MeshFunctionSharedPtr<Scalar> > dummy_fns;
232  for (unsigned short i = 0; i < StateReassemblyHelper<Scalar>::current_number_of_equations; i++)
233  dummy_fns.push_back(new ZeroSolution<Scalar>(StateReassemblyHelper<Scalar>::current_prev_ref_spaces->at(i)->get_mesh()));
234  for (unsigned short i = 0; i < StateReassemblyHelper<Scalar>::current_number_of_equations; i++)
235  dummy_fns.push_back(new ZeroSolution<Scalar>(StateReassemblyHelper<Scalar>::current_ref_spaces->at(i)->get_mesh()));
236  // - (for reporting) count of DOFs needed to be reassembled
237  int reusable_DOFs_count = 0;
238 
239  // Start.
240  Hermes::Mixins::Loggable::Static::info("\t Handling Reusing matrix entries on the new Ref. Space:");
241  cpu_time.tick();
242 
243  // Find out if Dirichlet is not directly changed.
244  for (unsigned char space_i = 0; space_i < StateReassemblyHelper<Scalar>::current_number_of_equations; space_i++)
245  {
246  if (StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[space_i]->find(-1) == StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[space_i]->end())
247  (*StateReassemblyHelper<Scalar>::reusable_Dirichlet)[space_i] = true;
248  }
249 
250  // Traverse the previous and current reference Spaces at once.
251  Traverse trav(StateReassemblyHelper<Scalar>::current_number_of_equations * 2);
252  unsigned int num_states_local;
253  Traverse::State** states_local = trav.get_states(dummy_fns, num_states_local);
254  for (unsigned int local_state_i = 0; local_state_i < num_states_local; local_state_i++)
255  {
256  Traverse::State* current_local_state = states_local[local_state_i];
257  for (unsigned char space_i = 0; space_i < StateReassemblyHelper<Scalar>::current_number_of_equations; space_i++)
258  {
259  // Mark the appropriate elements
260  Element* prev_ref_element = current_local_state->e[space_i];
261  Element* ref_element = current_local_state->e[space_i + StateReassemblyHelper<Scalar>::current_number_of_equations];
262  // If the element is changed on the previous ref space, mark the appropriate element on the new ref space as to-reassemble.
263  bool element_added = false;
264  if (StateReassemblyHelper<Scalar>::current_elements_to_reassemble[space_i]->find(prev_ref_element->id) != StateReassemblyHelper<Scalar>::current_elements_to_reassemble[space_i]->end())
265  {
266  newSpace_elements_to_reassemble[space_i].insert(ref_element->id);
267  element_added = true;
268  }
269  // Get assembly lists.
270  prev_ref_spaces[space_i]->get_element_assembly_list(prev_ref_element, &al_prev);
271  ref_spaces[space_i]->get_element_assembly_list(ref_element, &al);
272  // Different assembly lists => reassemble element.
273  if (!element_added && al_prev.cnt != al.cnt)
274  {
275  newSpace_elements_to_reassemble[space_i].insert(ref_element->id);
276  element_added = true;
277  }
278 
279  // Fun begins here - we need to figure out which DOFs on the new reference spaces can be reused and which cannot.
280  unsigned short last_matched_index = 0;
281  bool contains_Dirichlet = false, anything_changed = al_prev.cnt != al.cnt;
282  for (unsigned short i_al_prev = 0; i_al_prev < al_prev.cnt; i_al_prev++)
283  {
284  bool reused = false;
285  if (!element_added && al_prev.idx[i_al_prev] != al.idx[i_al_prev])
286  {
287  newSpace_elements_to_reassemble[space_i].insert(ref_element->id);
288  element_added = true;
289  }
290  if (al_prev.dof[i_al_prev] < 0)
291  {
292  contains_Dirichlet = true;
293  continue;
294  }
295  for (unsigned short j_al = last_matched_index; j_al < al.cnt; j_al++)
296  {
297  if (al.dof[j_al] < 0)
298  {
299  contains_Dirichlet = true;
300  continue;
301  }
302  if (al_prev.idx[i_al_prev] == al.idx[j_al] && compare<Scalar>(-HermesEpsilon, al_prev.coef[i_al_prev] - al.coef[j_al]) && compare<Scalar>(al_prev.coef[i_al_prev] - al.coef[j_al], HermesEpsilon))
303  {
304  last_matched_index = j_al + 1;
305  if (StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[space_i]->find(al_prev.dof[i_al_prev]) == StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[space_i]->end())
306  {
307  if (!(*StateReassemblyHelper<Scalar>::reusable_DOFs)[al.dof[j_al]])
308  reusable_DOFs_count++;
309  (*StateReassemblyHelper<Scalar>::reusable_DOFs)[al.dof[j_al]] = true;
310  DOF_to_DOF_map[al_prev.dof[i_al_prev]] = al.dof[j_al];
311  reused = true;
312  }
313  break;
314  }
315  }
316  if (!reused)
317  {
318  assert(DOF_to_DOF_map[al_prev.dof[i_al_prev]] == -1);
319  anything_changed = true;
320  }
321  }
322  // Dirichlet - indirectly changed.
323  if (anything_changed && contains_Dirichlet)
324  (*StateReassemblyHelper<Scalar>::reusable_Dirichlet)[space_i] = false;
325  }
326  }
327 
328  // Now we have to add all elements containing Dirichlet DOF (changed or not)
329  if (StateReassemblyHelper<Scalar>::use_Dirichlet)
330  {
331  for (unsigned int local_state_i = 0; local_state_i < num_states_local; local_state_i++)
332  {
333  Traverse::State* current_local_state = states_local[local_state_i];
334  for (unsigned char space_i = 0; space_i < StateReassemblyHelper<Scalar>::current_number_of_equations; space_i++)
335  {
336  // If Dirichlet is not necessary to be recalculated, go on.
337  if ((*StateReassemblyHelper<Scalar>::reusable_Dirichlet)[space_i])
338  continue;
339  // Get current element.
340  Element* ref_element = current_local_state->e[space_i + StateReassemblyHelper<Scalar>::current_number_of_equations];
341  // If element is already being recalculated, continue.
342  if (newSpace_elements_to_reassemble[space_i].find(ref_element->id) != newSpace_elements_to_reassemble[space_i].end())
343  continue;
344 
345  // Mark the previous element.
346  Element* prev_ref_element = current_local_state->e[space_i];
347 
348  // Get assembly lists.
349  prev_ref_spaces[space_i]->get_element_assembly_list(prev_ref_element, &al_prev);
350  ref_spaces[space_i]->get_element_assembly_list(ref_element, &al);
351 
352  // Since the element has not been added before we know the length of the prev and current assembly lists is the same.
353  for (unsigned short al_i = 0; al_i < al_prev.cnt; al_i++)
354  {
355  if (al_prev.dof[al_i] < 0 || al.dof[al_i] < 0)
356  {
357  newSpace_elements_to_reassemble[space_i].insert(ref_element->id);
358  break;
359  }
360  }
361  }
362  }
363  }
364 
365  cpu_time.tick();
366  Hermes::Mixins::Loggable::Static::info("\t No. of DOFs to reassemble: %i / %i total - %2.0f%%.", ref_system_size - reusable_DOFs_count, ref_system_size, ((float)(ref_system_size - reusable_DOFs_count) / (float)ref_system_size) * 100.);
367  Hermes::Mixins::Loggable::Static::info("\t Search for elements to reassemble: %4.3f s", cpu_time.last());
368  cpu_time.tick();
369 
370  // Using the changed element on the new reference space, select the states from the original states that need to be recalculated.
371 #ifdef DEBUG_VIEWS
372  bool* reassembled_0 = (bool*)calloc(ref_spaces[0]->get_mesh()->get_max_element_id() + 1, sizeof(bool));
373  bool* reassembled_1 = (bool*)calloc(ref_spaces[1]->get_mesh()->get_max_element_id() + 1, sizeof(bool));
374 #endif
375  Traverse::State** new_states = malloc_with_check<Traverse::State*>(num_states, true);
376  int new_num_states = 0;
377  for (unsigned int state_i = 0; state_i < num_states; state_i++)
378  {
379  for (unsigned char space_i = 0; space_i < StateReassemblyHelper<Scalar>::current_number_of_equations; space_i++)
380  {
381  if (newSpace_elements_to_reassemble[space_i].find(states[state_i]->e[space_i]->id) != newSpace_elements_to_reassemble[space_i].end())
382  {
383  new_states[new_num_states++] = Traverse::State::clone(states[state_i]);
384 #ifdef DEBUG_VIEWS
385  reassembled_0[states[state_i]->e[0]->id] = true;
386  reassembled_1[states[state_i]->e[1]->id] = true;
387 #endif
388  break;
389  }
390  }
391  }
392 
393 #ifdef DEBUG_VIEWS
394  Views::ScalarView sc_temp_0("Reassembled states", new Views::WinGeom(600, 10, 600, 600));
395  Views::ScalarView sc_temp_1("Reassembled states", new Views::WinGeom(1230, 10, 600, 600));
396  MeshFunctionSharedPtr<double> reassembled_states_function_0(new ExactSolutionConstantArray<double, bool>(ref_spaces[0]->get_mesh(), reassembled_0));
397  MeshFunctionSharedPtr<double> reassembled_states_function_1(new ExactSolutionConstantArray<double, bool>(ref_spaces[1]->get_mesh(), reassembled_1));
398  sc_temp_0.show(reassembled_states_function_0);
399  sc_temp_1.show(reassembled_states_function_1);
401  ::free(reassembled_0);
402  ::free(reassembled_1);
403 #endif
404 
405  for (unsigned int i = 0; i < num_states; i++)
406  delete states[i];
407  free_with_check(states);
408  new_states = realloc_with_check<Traverse::State*>(new_states, new_num_states);
409  states = new_states;
410 
411  cpu_time.tick();
412  Hermes::Mixins::Loggable::Static::info("\t No. of states to reassemble: %i / %i total - %2.0f%%.", new_num_states, num_states, ((float)new_num_states / (float)num_states) * 100.);
413  num_states = new_num_states;
414  Hermes::Mixins::Loggable::Static::info("\t Picking the new states: %4.3f s", cpu_time.last());
415  cpu_time.tick();
416 
417  // Now we have to use the DOF to DOF map to fill in the necessary entries in the new matrix and rhs from the old ones.
418  Scalar* Ax = StateReassemblyHelper<Scalar>::current_prev_mat->get_Ax();
419  int* Ai = StateReassemblyHelper<Scalar>::current_prev_mat->get_Ai();
420  int* Ap = StateReassemblyHelper<Scalar>::current_prev_mat->get_Ap();
421  Scalar* new_coeff_vec = nullptr;
422  if (coeff_vec)
423  new_coeff_vec = calloc_with_check<Scalar>(ref_system_size, true);
424  int total_entries = 0;
425  int used_entries = 0;
426  unsigned short current_row_entries;
427  for (unsigned int i = 0; i < prev_ref_system_size; i++)
428  {
429  current_row_entries = Ap[i + 1] - Ap[i];
430  total_entries += current_row_entries;
431  if (DOF_to_DOF_map[i] != -1)
432  {
433  for (int j = 0; j < current_row_entries; j++)
434  {
435  if (DOF_to_DOF_map[Ai[Ap[i] + j]] != -1)
436  {
437  mat->add(DOF_to_DOF_map[i], DOF_to_DOF_map[Ai[Ap[i] + j]], Ax[Ap[i] + j]);
438  used_entries++;
439  }
440  }
441  if (rhs)
442  rhs->add(DOF_to_DOF_map[i], StateReassemblyHelper<Scalar>::current_prev_rhs->get(i));
443  if (coeff_vec)
444  new_coeff_vec[DOF_to_DOF_map[i]] = coeff_vec[i];
445  }
446  }
447  if (dirichlet_lift_rhs && StateReassemblyHelper<Scalar>::use_Dirichlet)
448  {
449  unsigned int running_count = 0;
450  for (unsigned short space_i = 0; space_i < StateReassemblyHelper<Scalar>::current_number_of_equations; space_i++)
451  {
452  if ((*StateReassemblyHelper<Scalar>::reusable_Dirichlet)[space_i])
453  {
454  for (unsigned int dof_i = running_count; dof_i < running_count + prev_ref_spaces[space_i]->get_num_dofs(); dof_i++)
455  {
456  if (DOF_to_DOF_map[dof_i] != -1)
457  dirichlet_lift_rhs->add(DOF_to_DOF_map[dof_i], StateReassemblyHelper<Scalar>::current_prev_dirichlet_lift_rhs->get(dof_i));
458  }
459  }
460  running_count += prev_ref_spaces[space_i]->get_num_dofs();
461  }
462  }
463 
464  if (coeff_vec)
465  {
466  free_with_check(coeff_vec, true);
467  coeff_vec = new_coeff_vec;
468  }
469  cpu_time.tick();
470  Hermes::Mixins::Loggable::Static::info("\t Reused matrix entries: %i / %i total - %2.0f%%.", used_entries, total_entries, ((float)used_entries / (float)total_entries) * 100.);
471  Hermes::Mixins::Loggable::Static::info("\t Copying the linear system: %4.3f s", cpu_time.last());
472  free_with_check(DOF_to_DOF_map);
473  }
474 
475  template<typename Scalar, typename SolverType>
476  void AdaptSolver<Scalar, SolverType>::init_solving(AdaptivityType adaptivityType)
477  {
478  this->adaptivity_step = 1;
479  this->solve_method_running = true;
480  ref_slns.clear();
481  slns.clear();
482  for (unsigned char i = 0; i < this->spaces.size(); i++)
483  {
484  ref_slns.push_back(MeshFunctionSharedPtr<Scalar>(new Solution<Scalar>));
485  slns.push_back(MeshFunctionSharedPtr<Scalar>(new Solution<Scalar>));
486  if (this->visualization)
487  {
488  this->scalar_views.push_back(new Views::ScalarView("", new Views::WinGeom(i * 410, 0, 300, 300)));
489  this->scalar_views.back()->get_linearizer()->set_criterion(Views::LinearizerCriterionFixed(4));
490  this->scalar_views.back()->set_title("Reference solution #%i", i);
491 
492  this->order_views.push_back(new Views::OrderView("", new Views::WinGeom(i * 410, 320, 300, 300)));
493  this->order_views.back()->set_title("Reference space #%i - orders", i);
494 
495  this->base_views.push_back(new Views::BaseView<Scalar>("", new Views::WinGeom(i * 410, 640, 300, 300)));
496  this->base_views.back()->get_linearizer()->set_criterion(Views::LinearizerCriterionFixed(4));
497  }
498  }
499 
500  this->solver->set_verbose_output(this->get_verbose_output());
501  //this->solver->output_matrix();
502  this->solver->set_matrix_export_format(EXPORT_FORMAT_MATLAB_SIMPLE);
503 
504  //this->solver->output_rhs();
505  this->solver->set_rhs_export_format(EXPORT_FORMAT_MATLAB_SIMPLE);
506 
507  this->adaptivity_internal = new Adapt<Scalar>(spaces, error_calculator, stopping_criterion_single_step);
508  this->adaptivity_internal->set_verbose_output(this->get_verbose_output());
509 
510  StateReassemblyHelper<Scalar>::reusable_DOFs = new bool*;
511  StateReassemblyHelper<Scalar>::reusable_Dirichlet = new bool*;
512  this->solver->dp->set_reusable_DOFs(StateReassemblyHelper<Scalar>::reusable_DOFs, StateReassemblyHelper<Scalar>::reusable_Dirichlet);
513  StateReassemblyHelper<Scalar>::use_Dirichlet = this->solver->dp->add_dirichlet_lift;
514  StateReassemblyHelper<Scalar>::current_number_of_equations = this->number_of_equations;
515 
516  this->ref_spaces.clear();
517 
518  if (adaptivityType == hAdaptivity)
519  {
520  for (unsigned char selector_i = 0; selector_i < this->spaces.size(); selector_i++)
521  hOnlySelectors.push_back(new RefinementSelectors::HOnlySelector<Scalar>());
522  }
523  if (adaptivityType == pAdaptivity)
524  {
525  for (unsigned char selector_i = 0; selector_i < this->spaces.size(); selector_i++)
526  pOnlySelectors.push_back(new RefinementSelectors::POnlySelector<Scalar>());
527  }
528  }
529 
530  template<typename Scalar, typename SolverType>
531  void AdaptSolver<Scalar, SolverType>::deinit_solving()
532  {
533  this->solve_method_running = false;
534 
535  if (this->visualization)
536  for (unsigned short i = 0; i < this->number_of_equations; i++)
537  {
538  delete this->scalar_views[i];
539  delete this->order_views[i];
540  delete this->base_views[i];
541  }
542 
543  delete this->adaptivity_internal;
544  delete StateReassemblyHelper<Scalar>::reusable_DOFs;
545  delete StateReassemblyHelper<Scalar>::reusable_Dirichlet;
546 
547  for (unsigned char selector_i = 0; selector_i < this->hOnlySelectors.size(); selector_i++)
548  delete hOnlySelectors[selector_i];
549  hOnlySelectors.clear();
550  for (unsigned char selector_i = 0; selector_i < this->pOnlySelectors.size(); selector_i++)
551  delete pOnlySelectors[selector_i];
552  pOnlySelectors.clear();
553  }
554 
555  template<typename Scalar, typename SolverType>
557  {
558  // Initialization - allocations etc.
559  this->init_solving(adaptivityType);
560 
561  do
562  {
563  this->info("\tAdaptSolver step %d:", this->adaptivity_step);
564 
565  // Construct globally refined reference meshes and setup reference spaces.
566  prev_ref_spaces = ref_spaces;
567  ref_spaces.clear();
568  for (unsigned char i = 0; i < number_of_equations; i++)
569  {
570  Mesh::ReferenceMeshCreator ref_mesh_creator(spaces[i]->get_mesh());
571  MeshSharedPtr ref_mesh = ref_mesh_creator.create_ref_mesh();
572  typename Space<Scalar>::ReferenceSpaceCreator u_ref_space_creator(spaces[i], adaptivityType == pAdaptivity ? spaces[i]->get_mesh() : ref_mesh, adaptivityType == hAdaptivity ? 0 : 1);
573  ref_spaces.push_back(u_ref_space_creator.create_ref_space());
574  }
575 
576  // Set these to the solver.
577  this->solver->set_spaces(ref_spaces);
578 
579  // Initialize the states handler.
580  StateReassemblyHelper<Scalar>::current_iteration = this->adaptivity_step;
581  StateReassemblyHelper<Scalar>::current_ref_spaces = &ref_spaces;
582  StateReassemblyHelper<Scalar>::current_prev_ref_spaces = &prev_ref_spaces;
583  for (unsigned char i = 0; i < number_of_equations; i++)
584  {
585  StateReassemblyHelper<Scalar>::current_elements_to_reassemble[i] = &this->elements_to_reassemble[i];
586  StateReassemblyHelper<Scalar>::current_DOFs_to_reassemble[i] = &this->DOFs_to_reassemble[i];
587  }
588 
589  // Perform solution.
590  this->info("\tSolving on reference mesh, %i DOFs.", Space<Scalar>::get_num_dofs(ref_spaces));
591  this->solver->dp->set_reassembled_states_reuse_linear_system_fn(&get_states_to_reassemble<Scalar>);
592  if (adaptivity_step > 1 && dynamic_cast<NewtonSolver<Scalar>*>(this->solver))
593  {
594  Scalar* new_sln_vector = realloc_with_check<Scalar>(this->solver->sln_vector, Space<Scalar>::get_num_dofs(ref_spaces));
595  this->solver->sln_vector = nullptr;
596  memset(new_sln_vector + Space<Scalar>::get_num_dofs(prev_ref_spaces), 0, (Space<Scalar>::get_num_dofs(ref_spaces) - Space<Scalar>::get_num_dofs(prev_ref_spaces)) * sizeof(Scalar));
597  this->solver->solve(new_sln_vector);
598  free_with_check(new_sln_vector, true);
599  }
600  else
601  this->solver->solve();
602 
603  this->solver->get_linear_matrix_solver()->free();
604 
605  // Free reusable DOFs data structures for this run.
606  free_with_check<bool>(*StateReassemblyHelper<Scalar>::reusable_DOFs);
607  free_with_check<bool>(*StateReassemblyHelper<Scalar>::reusable_Dirichlet);
608 
609  // Update the stored (previous) linear system.
610  if (this->prev_mat)
611  delete this->prev_mat;
612  this->prev_mat = (Hermes::Algebra::CSCMatrix<Scalar>*)(this->solver->get_jacobian()->duplicate());
613  StateReassemblyHelper<Scalar>::current_prev_mat = this->prev_mat;
614 
615  if (this->prev_rhs)
616  delete this->prev_rhs;
617  this->prev_rhs = this->solver->get_residual()->duplicate();
618  if (this->solver->dp->add_dirichlet_lift)
619  this->prev_rhs->subtract_vector(this->solver->dp->dirichlet_lift_rhs);
620  StateReassemblyHelper<Scalar>::current_prev_rhs = this->prev_rhs;
621 
622  if (this->solver->dp->add_dirichlet_lift)
623  {
624  if (this->prev_dirichlet_lift_rhs)
625  delete this->prev_dirichlet_lift_rhs;
626  this->prev_dirichlet_lift_rhs = this->solver->dp->dirichlet_lift_rhs->duplicate();
627  StateReassemblyHelper<Scalar>::current_prev_dirichlet_lift_rhs = this->prev_dirichlet_lift_rhs;
628  }
629 
630  // Translate the resulting coefficient vector into the instance of Solution.
631  Solution<Scalar>::vector_to_solutions(solver->get_sln_vector(), ref_spaces, ref_slns);
632 
633  if (this->visualization)
634  this->visualize(ref_spaces);
635 
636  // Project the fine mesh solution onto the coarse mesh.
637  this->info("\tProjecting reference solution on coarse mesh.");
638  OGProjection<Scalar>::project_global(spaces, ref_slns, slns);
639 
640  // Calculate element errors.
641  if (!this->exact_slns.empty())
642  {
643  this->info("\tCalculating exact error.");
644  this->error_calculator->calculate_errors(slns, exact_slns, false);
645  double error = this->error_calculator->get_total_error_squared() * 100;
646  this->info("\tExact error: %f.", error);
647  }
648 
649  this->info("\tCalculating error estimate.");
650  this->error_calculator->calculate_errors(slns, ref_slns, true);
651  double error = this->error_calculator->get_total_error_squared() * 100;
652  this->info("\tThe error estimate: %f.", error);
653 
654  // If err_est too large, adapt the mesh.
655  if (this->stopping_criterion_global->done(error, this->adaptivity_step))
656  {
657  this->deinit_solving();
658  return;
659  }
660  else
661  {
662  this->info("\tAdapting coarse mesh.");
663  total_elements_prev_spaces = 0;
664  for (unsigned short i = 0; i < number_of_equations; i++)
665  total_elements_prev_spaces += this->spaces[i]->get_mesh()->get_num_active_elements();
666  // For hp-adaptivity, we use the provided selectors.
667  if (adaptivityType == hpAdaptivity)
668  this->adaptivity_internal->adapt(this->selectors);
669  else if (adaptivityType == hAdaptivity)
670  this->adaptivity_internal->adapt(hOnlySelectors);
671  else
672  this->adaptivity_internal->adapt(pOnlySelectors);
673 
674  this->mark_elements_to_reassemble();
675  }
676 
677  this->adaptivity_step++;
678  this->info("\n");
679  } while (true);
680 
681  this->deinit_solving();
682  }
683 
684  template<typename Scalar, typename SolverType>
686  {
687  Hermes::Mixins::Loggable::Static::info("\t Marking elements to reassemble on the already used Ref. Space:");
688  this->tick();
689 
690  // Clear the arrays.
691  for (unsigned char i = 0; i < this->spaces.size(); i++)
692  {
693  this->elements_to_reassemble[i].clear();
694  this->DOFs_to_reassemble[i].clear();
695  }
696 
697  int total_elements_prev_ref_spaces = 0;
698  for (unsigned short i = 0; i < number_of_equations; i++)
699  total_elements_prev_ref_spaces += this->ref_spaces[i]->get_mesh()->get_num_active_elements();
700 
701  // Identify elements that changed.
702  int valid_elements_to_refine_count = 0;
703  int ref_elements_changed_count = 0;
704  for (int i = 0; i < this->adaptivity_internal->elements_to_refine_count; i++)
705  {
706  ElementToRefine* element_to_refine = &this->adaptivity_internal->elements_to_refine[i];
707  if (!element_to_refine->valid)
708  continue;
709  valid_elements_to_refine_count++;
710  RefinementType refinement_type = element_to_refine->split;
711  int component = element_to_refine->comp;
712  Element* e = this->ref_spaces[component]->get_mesh()->get_element_fast(element_to_refine->id);
713  if (e->active)
714  {
715  this->elements_to_reassemble[component].insert(e->id);
716  ref_elements_changed_count++;
717  }
718  else
719  {
720  for (int son_i = 0; son_i < H2D_MAX_ELEMENT_SONS; son_i++)
721  {
722  this->elements_to_reassemble[component].insert(e->sons[son_i]->id);
723  ref_elements_changed_count++;
724  }
725  }
726  }
727  Hermes::Mixins::Loggable::Static::info("\t No. of coarse mesh elements refined: %i / %i total - %2.0f%%.", valid_elements_to_refine_count, total_elements_prev_spaces, ((float)valid_elements_to_refine_count / (float)total_elements_prev_spaces) * 100.);
728  Hermes::Mixins::Loggable::Static::info("\t No. of fine mesh elements directly changed: %i / %i total - %2.0f%%.", ref_elements_changed_count, total_elements_prev_ref_spaces, ((float)ref_elements_changed_count / (float)total_elements_prev_ref_spaces) * 100.);
729  this->tick();
730  Hermes::Mixins::Loggable::Static::info("\t Identify elements that changed: %4.3f s", this->last());
731  this->tick();
732 
733  // Identify DOFs of the changed elements.
734  AsmList<Scalar> al;
735  for (unsigned char space_i = 0; space_i < this->number_of_equations; space_i++)
736  {
737  for (std::unordered_set<unsigned int>::iterator it = elements_to_reassemble[space_i].begin(); it != elements_to_reassemble[space_i].end(); ++it)
738  {
739  Element* e = this->ref_spaces[space_i]->get_mesh()->get_element_fast(*it);
740  this->ref_spaces[space_i]->get_element_assembly_list(e, &al);
741  for (int j = 0; j < al.cnt; j++)
742  this->DOFs_to_reassemble[space_i].insert(al.dof[j]);
743  }
744  }
745 
746  this->tick();
747  Hermes::Mixins::Loggable::Static::info("\t Identify DOFs that changed: %4.3f s", this->last());
748  this->tick();
749 
750  // Take a look at other elements if they share a DOF that changed.
752  ref_elements_changed_count = 0;
753  for (unsigned char space_i = 0; space_i < this->number_of_equations; space_i++)
754  {
755  for_all_active_elements_fast(this->ref_spaces[space_i]->get_mesh())
756  {
757  this->ref_spaces[space_i]->get_element_assembly_list(e, &al);
758  for (int j = 0; j < al.cnt; j++)
759  {
760  if (this->DOFs_to_reassemble[space_i].find(al.dof[j]) != this->DOFs_to_reassemble[space_i].end())
761  {
762  this->elements_to_reassemble[space_i].insert(e->id);
763  ref_elements_changed_count++;
764  break;
765  }
766  }
767  }
768  }
769 
770  Hermes::Mixins::Loggable::Static::info("\t No. of all fine mesh elements that need to be reassembled: %i / %i total - %2.0f%%.", ref_elements_changed_count, total_elements_prev_ref_spaces, ((float)ref_elements_changed_count / (float)total_elements_prev_ref_spaces) * 100.);
771  this->tick();
772  Hermes::Mixins::Loggable::Static::info("\t Looking for elements containing a changed DOF: %4.3f s", this->last());
773  }
774 
775  template<typename Scalar, typename SolverType>
776  void AdaptSolver<Scalar, SolverType>::visualize(std::vector<SpaceSharedPtr<Scalar> >& ref_spaces)
777  {
778  for (unsigned short i = 0; i < this->number_of_equations; i++)
779  {
780  this->scalar_views[i]->show(this->ref_slns[i]);
781  this->order_views[i]->show(ref_spaces[i]);
782  this->base_views[i]->show(ref_spaces[i]);
783  }
784 
785  if (this->wait_for_keypress)
787  }
788 
789  template<typename Scalar, typename SolverType>
790  std::vector<MeshFunctionSharedPtr<Scalar> > AdaptSolver<Scalar, SolverType>::get_slns()
791  {
792  if (this->solve_method_running)
793  throw Exceptions::Exception("AdaptSolver asked for solutions while it was running.");
794  return this->slns;
795  }
796 
797  template<typename Scalar, typename SolverType>
799  {
800  if (this->solve_method_running)
801  throw Exceptions::Exception("AdaptSolver asked for a solution while it was running.");
802  return this->slns[index];
803  }
804 
805  template<typename Scalar, typename SolverType>
806  std::vector<MeshFunctionSharedPtr<Scalar> > AdaptSolver<Scalar, SolverType>::get_ref_slns()
807  {
808  if (this->solve_method_running)
809  throw Exceptions::Exception("AdaptSolver asked for solutions while it was running.");
810  return this->ref_slns;
811  }
812 
813  template<typename Scalar, typename SolverType>
815  {
816  if (this->solve_method_running)
817  throw Exceptions::Exception("AdaptSolver asked for a solution while it was running.");
818  return this->ref_slns[index];
819  }
820 
821  template<typename Scalar, typename SolverType>
823  {
824  return this->stopping_criterion_global;
825  }
826 
827  template<typename Scalar, typename SolverType>
828  void AdaptSolver<Scalar, SolverType>::set_stopping_criterion_global(AdaptSolverCriterion* stopping_criterion_global)
829  {
830  this->stopping_criterion_global = stopping_criterion_global;
831  }
832 
833  template<typename Scalar, typename SolverType>
835  {
836  if (this->solve_method_running)
837  throw Exceptions::Exception("AdaptSolver asked to change the exact_slns while it was running.");
838  this->exact_slns = exact_slns;
839  }
840 
841  template<typename Scalar, typename SolverType>
843  {
844  if (this->solve_method_running)
845  throw Exceptions::Exception("AdaptSolver asked to change the initial spaces while it was running.");
846  Helpers::check_length(this->spaces, spaces);
847  this->spaces = spaces;
848 
849  this->adaptivity_internal->set_spaces(this->spaces);
850  this->solver->set_spaces(this->spaces);
851  }
852 
853  template<typename Scalar, typename SolverType>
855  {
856  if (this->solve_method_running)
857  throw Exceptions::Exception("AdaptSolver asked to change the weak formulation while it was running.");
858  this->wf = wf;
859  this->solver->set_weak_formulation(wf);
860  }
861 
862  template<typename Scalar, typename SolverType>
863  void AdaptSolver<Scalar, SolverType>::set_error_calculator(ErrorCalculator<Scalar>* error_calculator)
864  {
865  this->error_calculator = error_calculator;
866  }
867 
868  template<typename Scalar, typename SolverType>
869  void AdaptSolver<Scalar, SolverType>::set_stopping_criterion_single_step(AdaptivityStoppingCriterion<Scalar>* stopping_criterion_single_step)
870  {
871  this->stopping_criterion_single_step = stopping_criterion_single_step;
872  this->adaptivity_internal->set_strategy(stopping_criterion_single_step);
873  }
874 
875  template<typename Scalar, typename SolverType>
876  void AdaptSolver<Scalar, SolverType>::set_selectors(std::vector<RefinementSelectors::Selector<Scalar>*> selectors)
877  {
878  Helpers::check_length(this->selectors, selectors);
879  this->selectors = selectors;
880  }
881 
882  template<typename Scalar, typename SolverType>
883  std::vector<SpaceSharedPtr<Scalar> > AdaptSolver<Scalar, SolverType>::get_initial_spaces()
884  {
885  return this->spaces;
886  }
887 
888  template<typename Scalar, typename SolverType>
889  WeakFormSharedPtr<Scalar> AdaptSolver<Scalar, SolverType>::get_wf()
890  {
891  return this->wf;
892  }
893 
894  template<typename Scalar, typename SolverType>
896  {
897  return this->solver;
898  }
899 
900  template<typename Scalar, typename SolverType>
902  {
903  return this->error_calculator;
904  }
905 
906  template<typename Scalar, typename SolverType>
907  AdaptivityStoppingCriterion<Scalar>* AdaptSolver<Scalar, SolverType>::get_stopping_criterion_single_step()
908  {
909  return this->stopping_criterion_single_step;
910  }
911 
912  template<typename Scalar, typename SolverType>
913  std::vector<RefinementSelectors::Selector<Scalar>*> AdaptSolver<Scalar, SolverType>::get_selectors()
914  {
915  return this->selectors;
916  }
917 
918  template<typename Scalar, typename SolverType>
919  bool AdaptSolver<Scalar, SolverType>::isOkay() const
920  {
921  this->adaptivity_internal->check();
922  for (unsigned short i = 0; i < this->number_of_equations; i++)
923  this->spaces[i]->check();
924 
925  return true;
926  }
927 
928  template HERMES_API class AdaptSolver < double, LinearSolver<double> > ;
929  template HERMES_API class AdaptSolver < std::complex<double>, LinearSolver<std::complex<double > > > ;
930 
938  }
939 }
Definition: adapt.h:24
AdaptSolver(std::vector< SpaceSharedPtr< Scalar > > initial_spaces, WeakFormSharedPtr< Scalar > wf, ErrorCalculator< Scalar > *error_calculator, AdaptivityStoppingCriterion< Scalar > *stopping_criterion_single_step, std::vector< RefinementSelectors::Selector< Scalar > * > selectors, AdaptSolverCriterion *stopping_criterion_global)
Constructor.
virtual void set_verbose_output(bool to_set)
See Hermes::Mixins::Loggable.
void solve(AdaptivityType adaptivityType)
The main method - solve.
void switch_visualization(bool on_off, bool wait_for_keypress)
Switch visualization on / off.
SolverType * get_solver()
Getters.
Used to pass the instances of Space around.
Definition: space.h:34
RefinementType
Possible refinements of an element.
MeshFunctionSharedPtr< Scalar > get_ref_sln(int index)
Get i-th solution.
int get_num_dofs() const
Returns the number of basis functions contained in the space.
Definition: space.cpp:286
File containing ScalarView class.
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
~AdaptSolver()
Destruct this instance.
std::vector< MeshFunctionSharedPtr< Scalar > > get_slns()
Get the solutions.
Used to pass the instances of WeakForm around.
Definition: weakform.h:55
virtual SpaceSharedPtr< Scalar > create_ref_space(bool assign_dofs=true)
Methods that user calls to get the reference space pointer (has to be properly casted if necessary)...
Definition: space.cpp:658
void set_initial_spaces(std::vector< SpaceSharedPtr< Scalar > >)
Setters.
void set_exact_solutions(std::vector< MeshFunctionSharedPtr< Scalar > > exact_slns)
Add exact solutions for exact solver calculation.
Evaluation of an error between a (coarse) solution and a reference solution.
Definition: adapt.h:28
Class for creating reference space.
Definition: space.h:296
static void wait_for_keypress(const char *text=nullptr)
Waits for keypress. Deprecated.
Definition: view.cpp:516
Represents a finite element space over a domain.
Definition: api2d.h:34
A parent of all refinement selectors. Abstract class.
Definition: function.h:29
#define H2D_MAX_ELEMENT_SONS
Macros.
Definition: global.h:30
MeshFunctionSharedPtr< Scalar > get_sln(int index)
Get i-th solution.
std::vector< MeshFunctionSharedPtr< Scalar > > get_ref_slns()
Get the solutions.
Class for creating reference mesh.
Definition: mesh.h:209
::xsd::cxx::tree::error< char > error
Error condition.
virtual MeshSharedPtr create_ref_mesh()
Definition: mesh.cpp:60
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.
void init()
Common code for the constructors.