Hermes2D  3.0
discrete_problem_selective_assembler.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/discrete_problem_selective_assembler.h"
17 #include "neighbor_search.h"
18 
19 namespace Hermes
20 {
21  namespace Hermes2D
22  {
23  template<typename Scalar>
24  DiscreteProblemSelectiveAssembler<Scalar>::DiscreteProblemSelectiveAssembler()
25  : sp_seq(nullptr),
26  spaces_size(0),
27  matrix_structure_reusable(false),
28  previous_mat(nullptr),
29  vector_structure_reusable(false),
30  previous_rhs(nullptr)
31  {
32  }
33 
34  template<typename Scalar>
35  DiscreteProblemSelectiveAssembler<Scalar>::~DiscreteProblemSelectiveAssembler()
36  {
37  if (sp_seq)
38  delete[] sp_seq;
39  }
40 
41  template<typename Scalar>
42  bool DiscreteProblemSelectiveAssembler<Scalar>::prepare_sparse_structure(SparseMatrix<Scalar>* mat, Vector<Scalar>* rhs, std::vector<SpaceSharedPtr<Scalar> > spaces, Traverse::State**& states, unsigned int& num_states)
43  {
44  int ndof = Space<Scalar>::get_num_dofs(spaces);
45 
46  if (matrix_structure_reusable && mat && mat == this->previous_mat)
47  mat->zero();
48 
49  if (vector_structure_reusable && rhs && rhs == this->previous_rhs)
50  {
51  if (rhs->get_size() == 0)
52  rhs->alloc(ndof);
53  else
54  rhs->zero();
55  }
56 
57  if ((!matrix_structure_reusable || (mat != this->previous_mat)) && mat)
58  {
59  // Spaces have changed: create the matrix from scratch.
60  matrix_structure_reusable = true;
61  mat->free();
62  mat->prealloc(ndof);
63 
64  AsmList<Scalar>* al = malloc_with_check<AsmList<Scalar> >(spaces_size);
65  int* dofs_m, *dofs_n;
66  unsigned int cnts_m, cnts_n;
67  bool **blocks = this->wf->get_blocks(this->force_diagonal_blocks);
68 
69  // Loop through all elements.
70  this->tick();
71  for (unsigned int state_i = 0; state_i < num_states; state_i++)
72  {
73  Traverse::State* current_state = states[state_i];
74 
75  // Obtain assembly lists for the element at all spaces.
77  for (unsigned int i = 0; i < spaces_size; i++)
78  {
79  if (current_state->e[i])
80  spaces[i]->get_element_assembly_list(current_state->e[i], &(al[i]));
81  }
82  if (this->wf->is_DG() && !this->wf->mfDG.empty())
83  {
84  // Number of edges ( = number of vertices).
85  int num_edges = current_state->e[0]->nvert;
86 
87  // Allocation an array of arrays of neighboring elements for every mesh x edge.
88  Element **** neighbor_elems_arrays = new Element ***[spaces_size];
89  for (unsigned int i = 0; i < spaces_size; i++)
90  neighbor_elems_arrays[i] = new Element **[num_edges];
91 
92  // The same, only for number of elements
93  int ** neighbor_elems_counts = new int *[spaces_size];
94  for (unsigned int i = 0; i < spaces_size; i++)
95  neighbor_elems_counts[i] = new int[num_edges];
96 
97  // Get the neighbors.
98  for (unsigned int el = 0; el < spaces_size; el++)
99  {
100  NeighborSearch<Scalar> ns(current_state->e[el], spaces[el]->get_mesh());
101 
102  for (int ed = 0; ed < num_edges; ed++)
103  {
104  if (current_state->e[el]->en[ed]->bnd)
105  continue;
106 
107  ns.set_active_edge(ed);
108  const std::vector<Element *> *neighbors = ns.get_neighbors();
109 
110  neighbor_elems_counts[el][ed] = ns.get_num_neighbors();
111  neighbor_elems_arrays[el][ed] = new Element *[neighbor_elems_counts[el][ed]];
112  for (int neigh = 0; neigh < neighbor_elems_counts[el][ed]; neigh++)
113  neighbor_elems_arrays[el][ed][neigh] = (*neighbors)[neigh];
114  }
115  }
116 
117  // Pre-add into the stiffness matrix.
118  for (unsigned int m = 0; m < spaces_size; m++)
119  {
120  for (unsigned int el = 0; el < spaces_size; el++)
121  {
122  for (int ed = 0; ed < num_edges; ed++)
123  {
124  if (current_state->e[el]->en[ed]->bnd)
125  continue;
126 
127  for (int neigh = 0; neigh < neighbor_elems_counts[el][ed]; neigh++)
128  {
129  if ((blocks[m][el] || blocks[el][m]) && current_state->e[m])
130  {
131  AsmList<Scalar>*am = &(al[m]);
133  spaces[el]->get_element_assembly_list(neighbor_elems_arrays[el][ed][neigh], an);
134 
135  // pretend assembling of the element stiffness matrix
136  // register nonzero elements
137  for (unsigned int i = 0; i < am->cnt; i++)
138  {
139  if (am->dof[i] >= 0)
140  {
141  for (unsigned int j = 0; j < an->cnt; j++)
142  {
143  if (an->dof[j] >= 0)
144  {
145  if (blocks[m][el]) mat->pre_add_ij(am->dof[i], an->dof[j]);
146  if (blocks[el][m]) mat->pre_add_ij(an->dof[j], am->dof[i]);
147  }
148  }
149  }
150  }
151  delete an;
152  }
153  }
154  }
155  }
156  }
157 
158  // Deallocation an array of arrays of neighboring elements
159  // for every mesh x edge.
160  for (unsigned int el = 0; el < spaces_size; el++)
161  {
162  for (int ed = 0; ed < num_edges; ed++)
163  {
164  if (!current_state->e[el]->en[ed]->bnd)
165  delete[] neighbor_elems_arrays[el][ed];
166  }
167  delete[] neighbor_elems_arrays[el];
168  }
169  delete[] neighbor_elems_arrays;
170 
171  // The same, only for number of elements.
172  for (unsigned int el = 0; el < spaces_size; el++)
173  delete[] neighbor_elems_counts[el];
174  delete[] neighbor_elems_counts;
175  }
176 
177  // Go through all equation-blocks of the local stiffness matrix.
178  if (spaces_size == 1)
179  {
180  cnts_m = al[0].cnt;
181  dofs_m = al[0].dof;
182  if (blocks[0][0] && current_state->e[0])
183  {
184  for (unsigned int i = 0; i < cnts_m; i++)
185  {
186  if (dofs_m[i] >= 0)
187  {
188  for (unsigned int j = 0; j < cnts_m; j++)
189  if (dofs_m[j] >= 0)
190  mat->pre_add_ij(dofs_m[i], dofs_m[j]);
191  }
192  }
193  }
194  }
195  else
196  {
197  for (unsigned int m = 0; m < spaces_size; m++)
198  {
199  cnts_m = al[m].cnt;
200  dofs_m = al[m].dof;
201  for (unsigned int n = 0; n < spaces_size; n++)
202  {
203  if (blocks[m][n] && current_state->e[m] && current_state->e[n])
204  {
205  cnts_n = al[n].cnt;
206  dofs_n = al[n].dof;
207 
208  // Pretend assembling of the element stiffness matrix.
209  for (unsigned int i = 0; i < cnts_m; i++)
210  {
211  if (dofs_m[i] >= 0)
212  for (unsigned int j = 0; j < cnts_n; j++)
213  if (dofs_n[j] >= 0)
214  mat->pre_add_ij(dofs_m[i], dofs_n[j]);
215  }
216  }
217  }
218  }
219  }
220  }
221  this->tick();
222  this->info("\tDiscreteProblemSelectiveAssembler: Loop: %s.", this->last_str().c_str());
223 
224  this->tick();
225 
226  free_with_check(al);
227  free_with_check(blocks, true);
228  mat->alloc();
229 
230  this->tick();
231  this->info("\tDiscreteProblemSelectiveAssembler: Finish: %s.", this->last_str().c_str());
232  }
233 
234  // WARNING: unlike Matrix<Scalar>::alloc(), Vector<Scalar>::alloc(ndof) frees the memory occupied
235  // by previous vector before allocating
236  if ((!vector_structure_reusable || (rhs != this->previous_rhs)) && rhs)
237  {
238  vector_structure_reusable = true;
239  rhs->alloc(ndof);
240  }
241 
242  previous_mat = mat;
243  previous_rhs = rhs;
244  return true;
245  }
246 
247  template<typename Scalar>
249  {
250  if (!sp_seq)
251  {
252  // Internal variables settings.
253  this->spaces_size = spacesToSet.size();
254  sp_seq = new int[spaces_size];
255  memset(sp_seq, -1, sizeof(int)* spaces_size);
256  }
257  else
258  {
259  for (unsigned int i = 0; i < spaces_size; i++)
260  {
261  int new_sp_seq = spacesToSet[i]->get_seq();
262 
263  if (new_sp_seq != sp_seq[i])
264  {
265  matrix_structure_reusable = false;
266  vector_structure_reusable = false;
267  }
268  sp_seq[i] = new_sp_seq;
269  }
270  }
271  }
272 
273  template<typename Scalar>
275  {
277 
278  this->matrix_structure_reusable = false;
279  this->vector_structure_reusable = false;
280 
281  if (spaces_size == 0)
282  return;
283  }
284 
285  template<typename Scalar>
287  {
288  if (current_state->e[form->i] && current_state->e[form->j])
289  {
290  if (fabs(form->scaling_factor) < Hermes::HermesSqrtEpsilon)
291  return false;
292 
293  // If a block scaling table is provided, and if the scaling coefficient
294  // A_mn for this block is zero, then the form does not need to be assembled.
295  if (this->block_weights)
296  if (fabs(this->block_weights->get_A(form->i / this->RK_original_spaces_count, form->j / this->RK_original_spaces_count)) < Hermes::HermesSqrtEpsilon)
297  return false;
298  return true;
299  }
300  return false;
301  }
302 
303  template<typename Scalar>
305  {
306  if (!form_to_be_assembled((MatrixForm<Scalar>*)form, current_state))
307  return false;
308 
309  if (form->assembleEverywhere)
310  return true;
311 
312  int this_marker = current_state->rep->marker;
313  for (unsigned int ss = 0; ss < form->areas_internal.size(); ss++)
314  if (form->areas_internal[ss] == this_marker)
315  return true;
316 
317  return false;
318  }
319 
320  template<typename Scalar>
322  {
323  if (!form_to_be_assembled((MatrixForm<Scalar>*)form, current_state))
324  return false;
325 
326  if (current_state->rep->en[current_state->isurf]->marker == 0)
327  return false;
328 
329  if (form->assembleEverywhere)
330  return true;
331 
332  int this_marker = current_state->rep->en[current_state->isurf]->marker;
333  for (unsigned int ss = 0; ss < form->areas_internal.size(); ss++)
334  if (form->areas_internal[ss] == this_marker)
335  return true;
336 
337  return false;
338  }
339 
340  template<typename Scalar>
342  {
343  return form_to_be_assembled((MatrixForm<Scalar>*)form, current_state);
344  }
345 
346  template<typename Scalar>
348  {
349  if (!current_state->e[form->i])
350  return false;
351  if (fabs(form->scaling_factor) < Hermes::HermesSqrtEpsilon)
352  return false;
353 
354  return true;
355  }
356 
357  template<typename Scalar>
359  {
360  if (!form_to_be_assembled((VectorForm<Scalar>*)form, current_state))
361  return false;
362 
363  if (form->assembleEverywhere)
364  return true;
365 
366  int this_marker = current_state->rep->marker;
367  for (unsigned int ss = 0; ss < form->areas_internal.size(); ss++)
368  if (form->areas_internal[ss] == this_marker)
369  return true;
370 
371  return false;
372  }
373 
374  template<typename Scalar>
376  {
377  if (!form_to_be_assembled((VectorForm<Scalar>*)form, current_state))
378  return false;
379 
380  if (current_state->rep->en[current_state->isurf]->marker == 0)
381  return false;
382 
383  if (form->assembleEverywhere)
384  return true;
385 
386  int this_marker = current_state->rep->en[current_state->isurf]->marker;
387  for (unsigned int ss = 0; ss < form->areas_internal.size(); ss++)
388  if (form->areas_internal[ss] == this_marker)
389  return true;
390 
391  return false;
392  }
393 
394  template<typename Scalar>
396  {
397  return form_to_be_assembled((VectorForm<Scalar>*)form, current_state);
398  }
399 
400  template class HERMES_API DiscreteProblemSelectiveAssembler < double > ;
402  }
403 }
bool prepare_sparse_structure(SparseMatrix< Scalar > *mat, Vector< Scalar > *rhs, std::vector< SpaceSharedPtr< Scalar > > spaces, Traverse::State **&states, unsigned int &num_states)
Definition: adapt.h:24
Abstract, base class for vector form - i.e. a single integral in the linear form on the right hand si...
Definition: weakform.h:439
int marker
element marker
Definition: element.h:144
Stores one element of a mesh.
Definition: element.h:107
Provides capabilities to (re-)assemble a matrix / vector only where necessary. See also Solver::keep_...
std::vector< int > areas_internal
Internal - this structure is being filled anew with every assembling.
Definition: weakform.h:310
Used to pass the instances of Space around.
Definition: space.h:34
int dof[H2D_MAX_LOCAL_BASIS_SIZE]
array of basis function numbers (DOFs)
Definition: asmlist.h:50
unsigned char nvert
number of vertices (3 or 4)
Definition: element.h:222
Abstract, base class for vector Surface form - i.e. VectorForm, where the integration is with respect...
Definition: weakform.h:48
int get_num_dofs() const
Returns the number of basis functions contained in the space.
Definition: space.cpp:286
Abstract, base class for vector DG form - i.e. linear Form, where the integration is with respect to ...
Definition: weakform.h:50
Node * en[H2D_MAX_NUMBER_EDGES]
edge node pointers
Definition: element.h:138
Abstract, base class for matrix Surface form - i.e. MatrixForm, where the integration is with respect...
Definition: weakform.h:47
unsigned short cnt
the number of items in the arrays idx, dof and coef
Definition: asmlist.h:54
Abstract, base class for matrix form - i.e. a single integral in the bilinear form on the left hand s...
Definition: weakform.h:357
Used to pass the instances of WeakForm around.
Definition: weakform.h:55
unsigned bnd
1 = boundary node; 0 = inner node
Definition: element.h:54
Abstract, base class for matrix Volumetric form - i.e. MatrixForm, where the integration is with resp...
Definition: weakform.h:45
This class characterizes a neighborhood of a given edge in terms of adjacent elements and provides me...
int marker
edge marker
Definition: element.h:68
void set_weak_formulation(WeakFormSharedPtr< Scalar > wf)
Set the weak forms.
Abstract, base class for matrix DG form - i.e. bilinear form, where the integration is with respect t...
Definition: weakform.h:49
bool form_to_be_assembled(MatrixForm< Scalar > *form, Traverse::State *current_state)
Decides if the form will be assembled on this State.
void set_spaces(std::vector< SpaceSharedPtr< Scalar > > spaces)
Sets new_ spaces for the instance.
Abstract, base class for vector Volumetric form - i.e. VectorForm, where the integration is with resp...
Definition: weakform.h:46