Hermes2D  3.0
discrete_problem.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 "discrete_problem/dg/discrete_problem_dg_assembler.h"
17 #include "discrete_problem/discrete_problem_helpers.h"
18 #include "discrete_problem/discrete_problem.h"
19 #include "function/exact_solution.h"
20 #include "mesh/traverse.h"
21 #include "space/space.h"
22 #include "function/solution.h"
23 #include "api2d.h"
24 
26 
27 namespace Hermes
28 {
29  namespace Hermes2D
30  {
31  template<typename Scalar>
32  DiscreteProblem<Scalar>::DiscreteProblem(WeakFormSharedPtr<Scalar> wf_, std::vector<SpaceSharedPtr<Scalar> > spaces, bool to_set, bool dirichlet_lift_accordingly)
33  {
34  this->init(to_set, dirichlet_lift_accordingly);
35  this->set_spaces(spaces);
36  this->set_weak_formulation(wf_);
37  }
38 
39  template<typename Scalar>
40  DiscreteProblem<Scalar>::DiscreteProblem(WeakFormSharedPtr<Scalar> wf_, SpaceSharedPtr<Scalar> space, bool to_set, bool dirichlet_lift_accordingly)
41  {
42  this->init(to_set, dirichlet_lift_accordingly);
43  this->set_space(space);
44  this->set_weak_formulation(wf_);
45  }
46 
47  template<typename Scalar>
48  DiscreteProblem<Scalar>::DiscreteProblem(bool to_set, bool dirichlet_lift_accordingly)
49  {
50  init(to_set, dirichlet_lift_accordingly);
51  }
52 
53  template<typename Scalar>
54  void DiscreteProblem<Scalar>::init(bool to_set, bool dirichlet_lift_accordingly)
55  {
56  this->reassembled_states_reuse_linear_system = nullptr;
57 
58  this->spaces_size = this->spaces.size();
59 
60  this->nonlinear = !to_set;
61  if (dirichlet_lift_accordingly)
62  this->add_dirichlet_lift = !this->nonlinear;
63  else
64  this->add_dirichlet_lift = this->nonlinear;
65 
66  if (this->add_dirichlet_lift)
67  this->dirichlet_lift_rhs = create_vector<Scalar>(false);
68  else
69  this->dirichlet_lift_rhs = nullptr;
70 
71  // Local number of threads - to avoid calling it over and over again, and against faults caused by the
72  // value being changed while assembling.
73  this->threadAssembler = new DiscreteProblemThreadAssembler<Scalar>*[this->num_threads_used];
74  for (int i = 0; i < this->num_threads_used; i++)
75  this->threadAssembler[i] = new DiscreteProblemThreadAssembler<Scalar>(&this->selectiveAssembler, this->nonlinear);
76  }
77 
78  template<typename Scalar>
80  {
81  for (int i = 0; i < this->num_threads_used; i++)
82  delete this->threadAssembler[i];
83  delete[] this->threadAssembler;
84 
85  if (this->dirichlet_lift_rhs)
86  delete this->dirichlet_lift_rhs;
87  }
88 
89  template<typename Scalar>
91  {
92  if (!this->wf)
93  return false;
94 
95  if (this->spaces_size == 0)
96  return false;
97 
98  // Initial check of meshes and spaces.
99  for (unsigned short space_i = 0; space_i < this->spaces_size; space_i++)
100  this->spaces[space_i]->check();
101 
102  for (unsigned short space_i = 0; space_i < this->spaces_size; space_i++)
103  if (!this->spaces[space_i]->is_up_to_date())
104  throw Exceptions::Exception("Space is out of date, if you manually refine it, you have to call assign_dofs().");
105 
106  return true;
107  }
108 
109  template<typename Scalar>
111  {
112  Loggable::set_verbose_output(to_set);
113  this->selectiveAssembler.set_verbose_output(to_set);
114  }
115 
116  template<typename Scalar>
118  {
120  this->wf->set_current_time(time);
121  }
122 
123  template<typename Scalar>
124  void DiscreteProblem<Scalar>::set_time_step(double time_step)
125  {
126  this->wf->set_current_time_step(time_step);
127  }
128 
129  template<typename Scalar>
130  std::vector<SpaceSharedPtr<Scalar> > DiscreteProblem<Scalar>::get_spaces()
131  {
132  return this->spaces;
133  }
134 
135  template<typename Scalar>
136  void DiscreteProblem<Scalar>::set_RK(int original_spaces_count, bool force_diagonal_blocks_, Table* block_weights_)
137  {
138  Mixins::DiscreteProblemRungeKutta<Scalar>::set_RK(original_spaces_count, force_diagonal_blocks_, block_weights_);
139 
140  this->selectiveAssembler.set_RK(original_spaces_count, force_diagonal_blocks_, block_weights_);
141 
142  for (int i = 0; i < this->num_threads_used; i++)
143  this->threadAssembler[i]->set_RK(original_spaces_count, force_diagonal_blocks_, block_weights_);
144  }
145 
146  template<typename Scalar>
148  {
149  this->selectiveAssembler.matrix_structure_reusable = false;
150  }
151 
152  template<typename Scalar>
154  {
156 
157  this->selectiveAssembler.set_weak_formulation(wf);
158  this->selectiveAssembler.matrix_structure_reusable = false;
159  }
160 
161  template<typename Scalar>
162  bool DiscreteProblem<Scalar>::set_matrix(SparseMatrix<Scalar>* mat)
163  {
165 
166  for (int i = 0; i < this->num_threads_used; i++)
167  this->threadAssembler[i]->set_matrix(mat);
168 
169  if (mat && this->current_mat != mat)
170  {
171  this->invalidate_matrix();
172  return false;
173  }
174  else
175  return true;
176  }
177 
178  template<typename Scalar>
179  bool DiscreteProblem<Scalar>::set_rhs(Vector<Scalar>* rhs)
180  {
182 
183  for (int i = 0; i < this->num_threads_used; i++)
184  {
185  this->threadAssembler[i]->set_rhs(rhs);
186  this->threadAssembler[i]->dirichlet_lift_rhs = this->dirichlet_lift_rhs;
187  }
188 
189  if (rhs && this->current_rhs != rhs)
190  {
191  this->invalidate_matrix();
192  return false;
193  }
194  else
195  return true;
196  }
197 
198  template<typename Scalar>
200  {
201  if (this->spaces_size > 0)
202  Helpers::check_length(spacesToSet, this->spaces_size);
203 
204  for (unsigned int i = 0; i < spacesToSet.size(); i++)
205  {
206  if (!spacesToSet[i])
207  throw Exceptions::NullException(0, i);
208  spacesToSet[i]->check();
209  }
210 
211  this->spaces_size = spacesToSet.size();
212  this->spaces = spacesToSet;
213 
214  this->selectiveAssembler.set_spaces(spacesToSet);
215 
216  for (int i = 0; i < this->num_threads_used; i++)
217  this->threadAssembler[i]->init_spaces(spaces);
218  }
219 
220  template<typename Scalar>
222  {
223  std::vector<SpaceSharedPtr<Scalar> > spaces;
224  spaces.push_back(space);
225  this->set_spaces(spaces);
226  }
227 
228  template<typename Scalar>
229  bool DiscreteProblem<Scalar>::assemble(SparseMatrix<Scalar>* mat, Vector<Scalar>* rhs)
230  {
231  Scalar* coeff_vec = nullptr;
232  return assemble(coeff_vec, mat, rhs);
233  }
234 
235  template<typename Scalar>
236  bool DiscreteProblem<Scalar>::assemble(Scalar*& coeff_vec, Vector<Scalar>* rhs)
237  {
238  return assemble(coeff_vec, nullptr, rhs);
239  }
240 
241  template<typename Scalar>
242  bool DiscreteProblem<Scalar>::assemble(Vector<Scalar>* rhs)
243  {
244  Scalar* coeff_vec = nullptr;
245  return assemble(coeff_vec, nullptr, rhs);
246  }
247 
248  template<typename Scalar>
249  void DiscreteProblem<Scalar>::init_assembling(Traverse::State**& states, unsigned int& num_states, std::vector<MeshSharedPtr>& meshes)
250  {
251  // Vector of meshes.
252  for (unsigned int space_i = 0; space_i < spaces.size(); space_i++)
253  meshes.push_back(spaces[space_i]->get_mesh());
254  for (unsigned int ext_i = 0; ext_i < this->wf->ext.size(); ext_i++)
255  meshes.push_back(this->wf->ext[ext_i]->get_mesh());
256  for (unsigned int form_i = 0; form_i < this->wf->get_forms().size(); form_i++)
257  for (unsigned int ext_i = 0; ext_i < this->wf->get_forms()[form_i]->ext.size(); ext_i++)
258  if (this->wf->get_forms()[form_i]->ext[ext_i])
259  meshes.push_back(this->wf->get_forms()[form_i]->ext[ext_i]->get_mesh());
260 
261  if (this->nonlinear)
262  {
263  for (unsigned int space_i = 0; space_i < spaces.size(); space_i++)
264  meshes.push_back(spaces[space_i]->get_mesh());
265  }
266 
267  // Important.
268  // This must be here, because the weakforms may have changed since set_weak_formulation (where the following calls
269  // used to be in development). And since the following clones the passed WeakForm, this has to be called
270  // only after the weak forms are ready for calculation.
271  for (unsigned char i = 0; i < this->num_threads_used; i++)
272  this->threadAssembler[i]->set_weak_formulation(this->wf);
273 
274  Traverse trav(this->spaces_size);
275  states = trav.get_states(meshes, num_states);
276 
277  // Init the caught parallel exception message.
278  this->exceptionMessageCaughtInParallelBlock.clear();
279 
280  // Dirichlet lift rhs part.
281  if (this->add_dirichlet_lift)
282  {
283  unsigned int ndof = Space<Scalar>::get_num_dofs(spaces);
284  this->dirichlet_lift_rhs->alloc(ndof);
285  }
286  }
287 
288  template<typename Scalar>
289  bool DiscreteProblem<Scalar>::assemble(Scalar*& coeff_vec, SparseMatrix<Scalar>* mat, Vector<Scalar>* rhs)
290  {
291  // Check.
292  this->check();
293  this->tick();
294 
295  // Set the matrices.
296  bool result = this->set_matrix(mat) && this->set_rhs(rhs);
297 
298  // Initialize states && previous iterations.
299  unsigned int num_states;
300  Traverse::State** states;
301  std::vector<MeshSharedPtr> meshes;
302  this->init_assembling(states, num_states, meshes);
303  this->tick();
304  this->info("\tDiscreteProblem: Initialization: %s.", this->last_str().c_str());
305  this->tick();
306 
307  // Creating matrix sparse structure.
308  // If there are no states, return.
309  if (this->selectiveAssembler.prepare_sparse_structure(this->current_mat, this->current_rhs, this->spaces, states, num_states))
310  {
311  this->tick();
312  this->info("\tDiscreteProblem: Prepare sparse structure: %s.", this->last_str().c_str());
313 
314  // The following does not make much sense to do just for rhs)
315  if (this->current_mat && this->reassembled_states_reuse_linear_system)
316  this->reassembled_states_reuse_linear_system(states, num_states, this->current_mat, this->current_rhs, this->dirichlet_lift_rhs, coeff_vec);
317 
318  Solution<Scalar>** u_ext_sln = nullptr;
319  if (this->nonlinear && coeff_vec)
320  {
321  u_ext_sln = new Solution<Scalar>*[spaces_size];
322  int first_dof = 0;
323  for (int i = 0; i < this->spaces_size; i++)
324  {
325  u_ext_sln[i] = new Solution<Scalar>(spaces[i]->get_mesh());
326  Solution<Scalar>::vector_to_solution(coeff_vec, spaces[i], u_ext_sln[i], !this->rungeKutta, first_dof);
327  first_dof += spaces[i]->get_num_dofs();
328  }
329  }
330 
331  if (num_states > 0)
332  {
333  // Is this a DG assembling.
334  bool is_DG = this->wf->is_DG();
335 
336 #pragma omp parallel num_threads(this->num_threads_used)
337  {
338  int thread_number = omp_get_thread_num();
339  int start = (num_states / this->num_threads_used) * thread_number;
340  int end = (num_states / this->num_threads_used) * (thread_number + 1);
341  if (thread_number == this->num_threads_used - 1)
342  end = num_states;
343 
344  try
345  {
346  this->threadAssembler[thread_number]->init_assembling(u_ext_sln, spaces, this->add_dirichlet_lift);
347 
349  if (is_DG)
350  dgAssembler = new DiscreteProblemDGAssembler<Scalar>(this->threadAssembler[thread_number], this->spaces, meshes);
351 
352  for (int state_i = start; state_i < end; state_i++)
353  {
354  // Exception already thrown -> exit the loop.
355  if (!this->exceptionMessageCaughtInParallelBlock.empty())
356  break;
357 
358  Traverse::State* current_state = states[state_i];
359 
360  this->threadAssembler[thread_number]->init_assembling_one_state(spaces, current_state);
361 
362  this->threadAssembler[thread_number]->assemble_one_state();
363 
364  if (is_DG)
365  {
366  dgAssembler->init_assembling_one_state(current_state);
367  dgAssembler->assemble_one_state();
368  dgAssembler->deinit_assembling_one_state();
369  }
370  this->threadAssembler[thread_number]->deinit_assembling_one_state();
371  }
372 
373  if (is_DG)
374  delete dgAssembler;
375 
376  this->threadAssembler[thread_number]->deinit_assembling();
377  }
378  catch (Hermes::Exceptions::Exception& e)
379  {
380 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
381  this->exceptionMessageCaughtInParallelBlock = e.info();
382  }
383  catch (std::exception& e)
384  {
385 #pragma omp critical (exceptionMessageCaughtInParallelBlock)
386  this->exceptionMessageCaughtInParallelBlock = e.what();
387  }
388  }
389  }
390 
391  if (this->nonlinear && coeff_vec)
392  {
393  for (int i = 0; i < this->spaces_size; i++)
394  delete u_ext_sln[i];
395  delete[] u_ext_sln;
396  }
397  }
398 
399  this->tick();
400 
401  // Deinitialize states && previous iterations.
402  this->deinit_assembling(states, num_states);
403 
404  // Finish the algebraic structures for solving.
405  if (this->current_mat)
406  this->current_mat->finish();
407  if (this->current_rhs)
408  this->current_rhs->finish();
409 
410  if (!this->exceptionMessageCaughtInParallelBlock.empty())
411  throw Hermes::Exceptions::Exception(this->exceptionMessageCaughtInParallelBlock.c_str());
412 
413  Element* e;
414  for (unsigned int space_i = 0; space_i < spaces.size(); space_i++)
415  {
416  for_all_active_elements(e, spaces[space_i]->get_mesh())
417  {
418  spaces[space_i]->edata[e->id].changed_in_last_adaptation = false;
419  e->visited = false;
420  }
421  }
422 
423  this->tick();
424  this->info("\tDiscreteProblem: De-initialization: %s.", this->last_str().c_str());
425 
426  return result;
427  }
428 
429  template<typename Scalar>
430  void DiscreteProblem<Scalar>::deinit_assembling(Traverse::State** states, unsigned int num_states)
431  {
432  for (unsigned int i = 0; i < num_states; i++)
433  delete states[i];
434  free_with_check(states);
435 
436  // Very important.
437  if (this->add_dirichlet_lift && this->current_rhs)
438  this->current_rhs->add_vector(this->dirichlet_lift_rhs);
439  }
440 
441  template class HERMES_API DiscreteProblem < double > ;
442  template class HERMES_API DiscreteProblem < std::complex<double> > ;
443  }
444 }
Definition: adapt.h:24
int id
element id number
Definition: element.h:112
Stores one element of a mesh.
Definition: element.h:107
bool visited
true if the element has been visited during assembling
Definition: element.h:120
::xsd::cxx::tree::exception< char > exception
Root of the C++/Tree exception hierarchy.
Used to pass the instances of Space around.
Definition: space.h:34
::xsd::cxx::tree::time< char, simple_type > time
C++ type corresponding to the time XML Schema built-in type.
Used to pass the instances of WeakForm around.
Definition: weakform.h:55
void deinit_assembling_one_state()
Deinitialize assembling for a state.
This class is a one-thread (non-DG) assembly worker.
Represents a finite element space over a domain.
Definition: api2d.h:34
void init_assembling_one_state(Traverse::State *current_state_)
Initialize assembling for a state.
State ** get_states(std::vector< MeshSharedPtr > meshes, unsigned int &states_count)
Definition: traverse.cpp:292
Represents the solution of a PDE.
Definition: api2d.h:35