Hermes2D  2.0
discrete_problem_linear.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_linear.h"
17 #include <iostream>
18 #include <algorithm>
19 #include "global.h"
20 #include "integrals/h1.h"
21 #include "quadrature/limit_order.h"
22 #include "mesh/traverse.h"
23 #include "space/space.h"
24 #include "shapeset/precalc.h"
25 #include "mesh/refmap.h"
26 #include "function/solution.h"
27 #include "neighbor.h"
28 #include "api2d.h"
29 
30 using namespace Hermes::Algebra::DenseMatrixOperations;
31 
32 namespace Hermes
33 {
34  namespace Hermes2D
35  {
36  template<typename Scalar>
37  DiscreteProblemLinear<Scalar>::DiscreteProblemLinear(const WeakForm<Scalar>* wf, Hermes::vector<const Space<Scalar> *> spaces) : DiscreteProblem<Scalar>(wf, spaces)
38  {
39  this->is_linear = true;
40  }
41 
42  template<typename Scalar>
44  {
45  this->is_linear = true;
46  }
47 
48  template<typename Scalar>
50  {
51  this->is_linear = true;
52  }
53 
54  template<typename Scalar>
56  {
57  }
58 
59  template<typename Scalar>
60  void DiscreteProblemLinear<Scalar>::assemble(SparseMatrix<Scalar>* mat,
61  Vector<Scalar>* rhs,
62  bool force_diagonal_blocks,
63  Table* block_weights)
64  {
65  // Check.
66  this->check();
67  if(this->ndof == 0)
68  throw Exceptions::Exception("Zero DOFs detected in DiscreteProblemLinear::assemble().");
69 
70  // Important, sets the current caughtException to NULL.
71  this->caughtException = NULL;
72 
73  this->current_mat = mat;
74  this->current_rhs = rhs;
75  this->current_force_diagonal_blocks = force_diagonal_blocks;
76  this->current_block_weights = block_weights;
77 
78  // Check that the block scaling table have proper dimension.
79  if(block_weights != NULL)
80  if(block_weights->get_size() != this->wf->get_neq())
81  throw Exceptions::LengthException(6, block_weights->get_size(),this-> wf->get_neq());
82 
83  // Creating matrix sparse structure.
84  this->create_sparse_structure();
85 
86  // Initial check of meshes and spaces.
87  for(unsigned int ext_i = 0; ext_i < this->wf->get_ext().size(); ext_i++)
88  {
89  if(!this->wf->get_ext()[ext_i]->isOkay())
90  throw Hermes::Exceptions::Exception("Ext function %d is not okay in assemble().", ext_i);
91  }
92 
93  // Structures that cloning will be done into.
94  PrecalcShapeset*** pss = new PrecalcShapeset**[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
95  PrecalcShapeset*** spss = new PrecalcShapeset**[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
96  RefMap*** refmaps = new RefMap**[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
97  AsmList<Scalar>*** als = new AsmList<Scalar>**[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
98  WeakForm<Scalar>** weakforms = new WeakForm<Scalar>*[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
99 
100  // Fill these structures.
101  this->init_assembling(NULL, pss, spss, refmaps, NULL, als, weakforms);
102 
103  // Vector of meshes.
104  Hermes::vector<const Mesh*> meshes;
105  for(unsigned int space_i = 0; space_i < this->spaces.size(); space_i++)
106  meshes.push_back(this->spaces[space_i]->get_mesh());
107  for(unsigned int ext_i = 0; ext_i < this->wf->ext.size(); ext_i++)
108  meshes.push_back(this->wf->ext[ext_i]->get_mesh());
109  for(unsigned int form_i = 0; form_i < this->wf->get_forms().size(); form_i++)
110  for(unsigned int ext_i = 0; ext_i < this->wf->get_forms()[form_i]->ext.size(); ext_i++)
111  if(this->wf->get_forms()[form_i]->ext[ext_i] != NULL)
112  meshes.push_back(this->wf->get_forms()[form_i]->ext[ext_i]->get_mesh());
113 
114  Traverse trav_master(true);
115  unsigned int num_states = trav_master.get_num_states(meshes);
116 
117  trav_master.begin(meshes.size(), &(meshes.front()));
118 
119  Traverse* trav = new Traverse[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
120  Hermes::vector<Transformable *>* fns = new Hermes::vector<Transformable *>[Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads)];
121  for(unsigned int i = 0; i < Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
122  {
123  for (unsigned j = 0; j < this->spaces.size(); j++)
124  fns[i].push_back(pss[i][j]);
125  for (unsigned j = 0; j < this->wf->ext.size(); j++)
126  {
127  fns[i].push_back(weakforms[i]->ext[j]);
128  weakforms[i]->ext[j]->set_quad_2d(&g_quad_2d_std);
129  }
130  for(unsigned int form_i = 0; form_i < this->wf->get_forms().size(); form_i++)
131  {
132  for(unsigned int ext_i = 0; ext_i < this->wf->get_forms()[form_i]->ext.size(); ext_i++)
133  if(this->wf->get_forms()[form_i]->ext[ext_i] != NULL)
134  {
135  fns[i].push_back(weakforms[i]->get_forms()[form_i]->ext[ext_i]);
136  weakforms[i]->get_forms()[form_i]->ext[ext_i]->set_quad_2d(&g_quad_2d_std);
137  }
138  }
139  trav[i].begin(meshes.size(), &(meshes.front()), &(fns[i].front()));
140  trav[i].stack = trav_master.stack;
141  }
142 
143  int state_i;
144 
145  PrecalcShapeset** current_pss;
146  PrecalcShapeset** current_spss;
147  RefMap** current_refmaps;
148  AsmList<Scalar>** current_als;
149  WeakForm<Scalar>* current_weakform;
150 
151 #define CHUNKSIZE 1
152  int num_threads_used = Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads);
153 #pragma omp parallel shared(trav_master, mat, rhs ) private(state_i, current_pss, current_spss, current_refmaps, current_als, current_weakform) num_threads(num_threads_used)
154  {
155 #pragma omp for schedule(dynamic, CHUNKSIZE)
156  for(state_i = 0; state_i < num_states; state_i++)
157  {
158  try
159  {
160  Traverse::State current_state;
161 
162 #pragma omp critical (get_next_state)
163  current_state = trav[omp_get_thread_num()].get_next_state(&trav_master.top, &trav_master.id);
164 
165  current_pss = pss[omp_get_thread_num()];
166  current_spss = spss[omp_get_thread_num()];
167  current_refmaps = refmaps[omp_get_thread_num()];
168  current_als = als[omp_get_thread_num()];
169  current_weakform = weakforms[omp_get_thread_num()];
170 
171  // One state is a collection of (virtual) elements sharing
172  // the same physical location on (possibly) different meshes.
173  // This is then the same element of the virtual union mesh.
174  // The proper sub-element mappings to all the functions of
175  // this stage is supplied by the function Traverse::get_next_state()
176  // called in the while loop.
177  this->assemble_one_state(current_pss, current_spss, current_refmaps, NULL, current_als, &current_state, current_weakform);
178 
179  if(this->DG_matrix_forms_present || this->DG_vector_forms_present)
180  this->assemble_one_DG_state(current_pss, current_spss, current_refmaps, NULL, current_als, &current_state, current_weakform->mfDG, current_weakform->vfDG, trav[omp_get_thread_num()].fn);
181  }
182  catch(Hermes::Exceptions::Exception& e)
183  {
184  if(this->caughtException == NULL)
185  this->caughtException = e.clone();
186  }
187  catch(std::exception& e)
188  {
189  if(this->caughtException == NULL)
190  this->caughtException = new Hermes::Exceptions::Exception(e.what());
191  }
192  }
193  }
194 
195  this->deinit_assembling(pss, spss, refmaps, NULL, als, weakforms);
196 
197  trav_master.finish();
198  for(unsigned int i = 0; i < Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
199  trav[i].finish();
200 
201  for(unsigned int i = 0; i < Hermes2DApi.get_integral_param_value(Hermes::Hermes2D::numThreads); i++)
202  {
203  fns[i].clear();
204  }
205  delete [] fns;
206  delete [] trav;
207 
209  if(this->current_mat != NULL)
210  this->current_mat->finish();
211  if(this->current_rhs != NULL)
212  this->current_rhs->finish();
213 
214  if(this->DG_matrix_forms_present || this->DG_vector_forms_present)
215  {
216  Element* element_to_set_nonvisited;
217  for(unsigned int mesh_i = 0; mesh_i < meshes.size(); mesh_i++)
218  for_all_elements(element_to_set_nonvisited, meshes[mesh_i])
219  element_to_set_nonvisited->visited = false;
220  }
221 
222  if(this->caughtException != NULL)
223  throw *(this->caughtException);
224  }
225 
226  template<typename Scalar>
228  AsmList<Scalar>* current_als_i, AsmList<Scalar>* current_als_j, Traverse::State* current_state, int n_quadrature_points, Geom<double>* geometry, double* jacobian_x_weights)
229  {
230  bool surface_form = (dynamic_cast<MatrixFormVol<Scalar>*>(form) == NULL);
231 
232  double block_scaling_coefficient = this->block_scaling_coeff(form);
233 
234  bool tra = (form->i != form->j) && (form->sym != 0);
235  bool sym = (form->i == form->j) && (form->sym == 1);
236 
237  // Assemble the local stiffness matrix for the form form.
238  Scalar **local_stiffness_matrix = new_matrix<Scalar>(std::max(current_als_i->cnt, current_als_j->cnt));
239 
240  Func<Scalar>** local_ext = ext;
241  // If the user supplied custom ext functions for this form.
242  if(form->ext.size() > 0)
243  {
244  int local_ext_count = form->ext.size();
245  local_ext = new Func<Scalar>*[local_ext_count];
246  for(int ext_i = 0; ext_i < local_ext_count; ext_i++)
247  if(form->ext[ext_i] != NULL)
248  local_ext[ext_i] = current_state->e[ext_i] == NULL ? NULL : init_fn(form->ext[ext_i], order);
249  else
250  local_ext[ext_i] = NULL;
251  }
252 
253  // Actual form-specific calculation.
254  for (unsigned int i = 0; i < current_als_i->cnt; i++)
255  {
256  if(current_als_i->dof[i] < 0)
257  continue;
258 
259  if((!tra || surface_form) && current_als_i->dof[i] < 0)
260  continue;
261  if(std::abs(current_als_i->coef[i]) < 1e-12)
262  continue;
263  if(!sym)
264  {
265  for (unsigned int j = 0; j < current_als_j->cnt; j++)
266  {
267  // Is this necessary, i.e. is there a coefficient smaller than 1e-12?
268  if(std::abs(current_als_j->coef[j]) < 1e-12)
269  continue;
270 
271  Func<double>* u = base_fns[j];
272  Func<double>* v = test_fns[i];
273 
274  if(current_als_j->dof[j] >= 0)
275  {
276  if(surface_form)
277  local_stiffness_matrix[i][j] = 0.5 * block_scaling_coefficient * form->value(n_quadrature_points, jacobian_x_weights, u_ext, u, v, geometry, local_ext) * form->scaling_factor * current_als_j->coef[j] * current_als_i->coef[i];
278  else
279  local_stiffness_matrix[i][j] = block_scaling_coefficient * form->value(n_quadrature_points, jacobian_x_weights, u_ext, u, v, geometry, local_ext) * form->scaling_factor * current_als_j->coef[j] * current_als_i->coef[i];
280  }
281  else
282  {
283  {
284  if(surface_form)
285  this->current_rhs->add(current_als_i->dof[i], -0.5 * block_scaling_coefficient * form->value(n_quadrature_points, jacobian_x_weights, u_ext, u, v, geometry, local_ext) * form->scaling_factor * current_als_j->coef[j] * current_als_i->coef[i]);
286  else
287  this->current_rhs->add(current_als_i->dof[i], -block_scaling_coefficient * form->value(n_quadrature_points, jacobian_x_weights, u_ext, u, v, geometry, local_ext) * form->scaling_factor * current_als_j->coef[j] * current_als_i->coef[i]);
288  }
289  }
290  }
291  }
292  // Symmetric block.
293  else
294  {
295  for (unsigned int j = 0; j < current_als_j->cnt; j++)
296  {
297  if(j < i && current_als_j->dof[j] >= 0)
298  continue;
299  // Is this necessary, i.e. is there a coefficient smaller than 1e-12?
300  if(std::abs(current_als_j->coef[j]) < 1e-12)
301  continue;
302 
303  Func<double>* u = base_fns[j];
304  Func<double>* v = test_fns[i];
305 
306  Scalar val = block_scaling_coefficient * form->value(n_quadrature_points, jacobian_x_weights, u_ext, u, v, geometry, local_ext) * form->scaling_factor * current_als_j->coef[j] * current_als_i->coef[i];
307 
308  if(current_als_j->dof[j] >= 0)
309  local_stiffness_matrix[i][j] = local_stiffness_matrix[j][i] = val;
310  else
311  {
312  this->current_rhs->add(current_als_i->dof[i], -val);
313  }
314  }
315  }
316  }
317 
318  // Insert the local stiffness matrix into the global one.
319  this->current_mat->add(current_als_i->cnt, current_als_j->cnt, local_stiffness_matrix, current_als_i->dof, current_als_j->dof);
320 
321  // Insert also the off-diagonal (anti-)symmetric block, if required.
322  if(tra)
323  {
324  if(form->sym < 0)
325  chsgn(local_stiffness_matrix, current_als_i->cnt, current_als_j->cnt);
326  transpose(local_stiffness_matrix, current_als_i->cnt, current_als_j->cnt);
327 
328  this->current_mat->add(current_als_j->cnt, current_als_i->cnt, local_stiffness_matrix, current_als_j->dof, current_als_i->dof);
329 
330  // Linear problems only: Subtracting Dirichlet lift contribution from the RHS:
331  for (unsigned int j = 0; j < current_als_i->cnt; j++)
332  if(current_als_i->dof[j] < 0)
333  for (unsigned int i = 0; i < current_als_j->cnt; i++)
334  if(current_als_j->dof[i] >= 0)
335  this->current_rhs->add(current_als_j->dof[i], -local_stiffness_matrix[i][j]);
336  }
337 
338  if(form->ext.size() > 0)
339  {
340  for(int ext_i = 0; ext_i < form->ext.size(); ext_i++)
341  if(form->ext[ext_i] != NULL)
342  {
343  local_ext[ext_i]->free_fn();
344  delete local_ext[ext_i];
345  }
346  delete [] local_ext;
347  }
348 
349  // Cleanup.
350  delete [] local_stiffness_matrix;
351  }
352 
353  template class HERMES_API DiscreteProblemLinear<double>;
354  template class HERMES_API DiscreteProblemLinear<std::complex<double> >;
355  }
356 }