Reference documentation for deal.II version 8.5.1
mg_transfer_matrix_free.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/logstream.h>
18 #include <deal.II/base/function.h>
19 
20 #include <deal.II/lac/la_parallel_vector.h>
21 #include <deal.II/grid/tria.h>
22 #include <deal.II/grid/tria_iterator.h>
23 #include <deal.II/dofs/dof_tools.h>
24 #include <deal.II/fe/fe.h>
25 #include <deal.II/dofs/dof_accessor.h>
26 #include <deal.II/multigrid/mg_tools.h>
27 #include <deal.II/multigrid/mg_transfer_matrix_free.h>
28 #include <deal.II/multigrid/mg_transfer_internal.h>
29 
30 #include <deal.II/matrix_free/tensor_product_kernels.h>
31 
32 #include <algorithm>
33 
34 DEAL_II_NAMESPACE_OPEN
35 
36 
37 template<int dim, typename Number>
39  :
40  fe_degree(0),
41  element_is_continuous(false),
42  n_components(0),
43  n_child_cell_dofs(0)
44 {}
45 
46 
47 
48 template<int dim, typename Number>
50  :
51  fe_degree(0),
52  element_is_continuous(false),
53  n_components(0),
54  n_child_cell_dofs(0)
55 {
56  this->mg_constrained_dofs = &mg_c;
57 }
58 
59 
60 
61 template <int dim, typename Number>
63 {}
64 
65 
66 
67 template <int dim, typename Number>
69 (const MGConstrainedDoFs &mg_c)
70 {
71  this->mg_constrained_dofs = &mg_c;
72 }
73 
74 
75 
76 template <int dim, typename Number>
78 {
80  fe_degree = 0;
81  element_is_continuous = false;
82  n_components = 0;
83  n_child_cell_dofs = 0;
84  level_dof_indices.clear();
85  parent_child_connect.clear();
86  dirichlet_indices.clear();
87  n_owned_level_cells.clear();
88  prolongation_matrix_1d.clear();
89  evaluation_data.clear();
90  weights_on_refined.clear();
91 }
92 
93 
94 template <int dim, typename Number>
96 (const DoFHandler<dim,dim> &mg_dof)
97 {
98  this->fill_and_communicate_copy_indices(mg_dof);
99 
100  std::vector<std::vector<Number> > weights_unvectorized;
101 
103 
104  internal::MGTransfer::setup_transfer<dim,Number>(mg_dof,
105  this->mg_constrained_dofs,
106  elem_info,
107  level_dof_indices,
108  parent_child_connect,
109  n_owned_level_cells,
110  dirichlet_indices,
111  weights_unvectorized,
112  this->copy_indices_global_mine,
113  this->ghosted_level_vector);
114  // unpack element info data
115  fe_degree = elem_info.fe_degree;
116  element_is_continuous = elem_info.element_is_continuous;
117  n_components = elem_info.n_components;
118  n_child_cell_dofs = elem_info.n_child_cell_dofs;
119 
120  // duplicate and put into vectorized array
121  prolongation_matrix_1d.resize(elem_info.prolongation_matrix_1d.size());
122  for (unsigned int i=0; i<elem_info.prolongation_matrix_1d.size(); i++)
123  prolongation_matrix_1d[i] = elem_info.prolongation_matrix_1d[i];
124 
125  // reshuffle into aligned vector of vectorized arrays
126  const unsigned int vec_size = VectorizedArray<Number>::n_array_elements;
127  const unsigned int n_levels = mg_dof.get_triangulation().n_global_levels();
128 
129  const unsigned int n_weights_per_cell = Utilities::fixed_power<dim>(3);
130  weights_on_refined.resize(n_levels-1);
131  for (unsigned int level = 1; level<n_levels; ++level)
132  {
133  weights_on_refined[level-1].resize(((n_owned_level_cells[level-1]+vec_size-1)/vec_size)*n_weights_per_cell);
134 
135  for (unsigned int c=0; c<n_owned_level_cells[level-1]; ++c)
136  {
137  const unsigned int comp = c/vec_size;
138  const unsigned int v = c%vec_size;
139  for (unsigned int i = 0; i<n_weights_per_cell; ++i)
140  {
141 
142  weights_on_refined[level-1][comp*n_weights_per_cell+i][v] = weights_unvectorized[level-1][c*n_weights_per_cell+i];
143  }
144  }
145  }
146 
147  evaluation_data.resize(3*n_child_cell_dofs);
148 }
149 
150 
151 
152 template <int dim, typename Number>
154 ::prolongate (const unsigned int to_level,
157 {
158  Assert ((to_level >= 1) && (to_level<=level_dof_indices.size()),
159  ExcIndexRange (to_level, 1, level_dof_indices.size()+1));
160 
161  AssertDimension(this->ghosted_level_vector[to_level].local_size(),
162  dst.local_size());
163  AssertDimension(this->ghosted_level_vector[to_level-1].local_size(),
164  src.local_size());
165 
166  this->ghosted_level_vector[to_level-1] = src;
167  this->ghosted_level_vector[to_level-1].update_ghost_values();
168  this->ghosted_level_vector[to_level] = 0.;
169 
170  // the implementation in do_prolongate_add is templated in the degree of the
171  // element (for efficiency reasons), so we need to find the appropriate
172  // kernel here...
173  if (fe_degree == 0)
174  do_prolongate_add<0>(to_level, this->ghosted_level_vector[to_level],
175  this->ghosted_level_vector[to_level-1]);
176  else if (fe_degree == 1)
177  do_prolongate_add<1>(to_level, this->ghosted_level_vector[to_level],
178  this->ghosted_level_vector[to_level-1]);
179  else if (fe_degree == 2)
180  do_prolongate_add<2>(to_level, this->ghosted_level_vector[to_level],
181  this->ghosted_level_vector[to_level-1]);
182  else if (fe_degree == 3)
183  do_prolongate_add<3>(to_level, this->ghosted_level_vector[to_level],
184  this->ghosted_level_vector[to_level-1]);
185  else if (fe_degree == 4)
186  do_prolongate_add<4>(to_level, this->ghosted_level_vector[to_level],
187  this->ghosted_level_vector[to_level-1]);
188  else if (fe_degree == 5)
189  do_prolongate_add<5>(to_level, this->ghosted_level_vector[to_level],
190  this->ghosted_level_vector[to_level-1]);
191  else if (fe_degree == 6)
192  do_prolongate_add<6>(to_level, this->ghosted_level_vector[to_level],
193  this->ghosted_level_vector[to_level-1]);
194  else if (fe_degree == 7)
195  do_prolongate_add<7>(to_level, this->ghosted_level_vector[to_level],
196  this->ghosted_level_vector[to_level-1]);
197  else if (fe_degree == 8)
198  do_prolongate_add<8>(to_level, this->ghosted_level_vector[to_level],
199  this->ghosted_level_vector[to_level-1]);
200  else if (fe_degree == 9)
201  do_prolongate_add<9>(to_level, this->ghosted_level_vector[to_level],
202  this->ghosted_level_vector[to_level-1]);
203  else if (fe_degree == 10)
204  do_prolongate_add<10>(to_level, this->ghosted_level_vector[to_level],
205  this->ghosted_level_vector[to_level-1]);
206  else
207  do_prolongate_add<-1>(to_level, this->ghosted_level_vector[to_level],
208  this->ghosted_level_vector[to_level-1]);
209 
210  this->ghosted_level_vector[to_level].compress(VectorOperation::add);
211  dst = this->ghosted_level_vector[to_level];
212 }
213 
214 
215 
216 template <int dim, typename Number>
218 ::restrict_and_add (const unsigned int from_level,
221 {
222  Assert ((from_level >= 1) && (from_level<=level_dof_indices.size()),
223  ExcIndexRange (from_level, 1, level_dof_indices.size()+1));
224 
225  AssertDimension(this->ghosted_level_vector[from_level].local_size(),
226  src.local_size());
227  AssertDimension(this->ghosted_level_vector[from_level-1].local_size(),
228  dst.local_size());
229 
230  this->ghosted_level_vector[from_level] = src;
231  this->ghosted_level_vector[from_level].update_ghost_values();
232  this->ghosted_level_vector[from_level-1] = 0.;
233 
234  if (fe_degree == 0)
235  do_restrict_add<0>(from_level, this->ghosted_level_vector[from_level-1],
236  this->ghosted_level_vector[from_level]);
237  else if (fe_degree == 1)
238  do_restrict_add<1>(from_level, this->ghosted_level_vector[from_level-1],
239  this->ghosted_level_vector[from_level]);
240  else if (fe_degree == 2)
241  do_restrict_add<2>(from_level, this->ghosted_level_vector[from_level-1],
242  this->ghosted_level_vector[from_level]);
243  else if (fe_degree == 3)
244  do_restrict_add<3>(from_level, this->ghosted_level_vector[from_level-1],
245  this->ghosted_level_vector[from_level]);
246  else if (fe_degree == 4)
247  do_restrict_add<4>(from_level, this->ghosted_level_vector[from_level-1],
248  this->ghosted_level_vector[from_level]);
249  else if (fe_degree == 5)
250  do_restrict_add<5>(from_level, this->ghosted_level_vector[from_level-1],
251  this->ghosted_level_vector[from_level]);
252  else if (fe_degree == 6)
253  do_restrict_add<6>(from_level, this->ghosted_level_vector[from_level-1],
254  this->ghosted_level_vector[from_level]);
255  else if (fe_degree == 7)
256  do_restrict_add<7>(from_level, this->ghosted_level_vector[from_level-1],
257  this->ghosted_level_vector[from_level]);
258  else if (fe_degree == 8)
259  do_restrict_add<8>(from_level, this->ghosted_level_vector[from_level-1],
260  this->ghosted_level_vector[from_level]);
261  else if (fe_degree == 9)
262  do_restrict_add<9>(from_level, this->ghosted_level_vector[from_level-1],
263  this->ghosted_level_vector[from_level]);
264  else if (fe_degree == 10)
265  do_restrict_add<10>(from_level, this->ghosted_level_vector[from_level-1],
266  this->ghosted_level_vector[from_level]);
267  else
268  // go to the non-templated version of the evaluator
269  do_restrict_add<-1>(from_level, this->ghosted_level_vector[from_level-1],
270  this->ghosted_level_vector[from_level]);
271 
272  this->ghosted_level_vector[from_level-1].compress(VectorOperation::add);
273  dst += this->ghosted_level_vector[from_level-1];
274 }
275 
276 
277 
278 namespace
279 {
280  template <int dim, typename Eval, typename Number, bool prolongate>
281  void
282  perform_tensorized_op(const Eval &evaluator,
283  const unsigned int n_child_cell_dofs,
284  const unsigned int n_components,
285  AlignedVector<VectorizedArray<Number> > &evaluation_data)
286  {
287  if (Eval::n_q_points != numbers::invalid_unsigned_int)
288  AssertDimension(n_components * Eval::n_q_points, n_child_cell_dofs);
289  VectorizedArray<Number> *t0 = &evaluation_data[0];
290  VectorizedArray<Number> *t1 = &evaluation_data[n_child_cell_dofs];
291  VectorizedArray<Number> *t2 = &evaluation_data[2*n_child_cell_dofs];
292 
293  for (unsigned int c=0; c<n_components; ++c)
294  {
295  // for the prolongate case, we go from dofs (living on the parent cell) to
296  // quads (living on all children) in the FEEvaluation terminology
297  if (dim == 1)
298  evaluator.template values<0,prolongate,false>(t0, t2);
299  else if (dim == 2)
300  {
301  evaluator.template values<0,prolongate,false>(t0, t1);
302  evaluator.template values<1,prolongate,false>(t1, t2);
303  }
304  else if (dim == 3)
305  {
306  evaluator.template values<0,prolongate,false>(t0, t2);
307  evaluator.template values<1,prolongate,false>(t2, t1);
308  evaluator.template values<2,prolongate,false>(t1, t2);
309  }
310  else
311  Assert(false, ExcNotImplemented());
312  if (prolongate)
313  {
314  t0 += Eval::dofs_per_cell;
315  t2 += Eval::n_q_points;
316  }
317  else
318  {
319  t0 += Eval::n_q_points;
320  t2 += Eval::dofs_per_cell;
321  }
322  }
323  }
324 
325  template <int dim, int degree, typename Number>
326  void weight_dofs_on_child (const VectorizedArray<Number> *weights,
327  const unsigned int n_components,
328  const unsigned int fe_degree,
330  {
331  Assert(fe_degree > 0, ExcNotImplemented());
332  Assert(fe_degree < 100, ExcNotImplemented());
333  const int loop_length = degree != -1 ? 2*degree+1 : 2*fe_degree+1;
334  unsigned int degree_to_3 [100];
335  degree_to_3[0] = 0;
336  for (int i=1; i<loop_length-1; ++i)
337  degree_to_3[i] = 1;
338  degree_to_3[loop_length-1] = 2;
339  for (unsigned int c=0; c<n_components; ++c)
340  for (int k=0; k<(dim>2 ? loop_length : 1); ++k)
341  for (int j=0; j<(dim>1 ? loop_length : 1); ++j)
342  {
343  const unsigned int shift = 9*degree_to_3[k] + 3*degree_to_3[j];
344  data[0] *= weights[shift];
345  // loop bound as int avoids compiler warnings in case loop_length
346  // == 1 (polynomial degree 0)
347  for (int i=1; i<loop_length-1; ++i)
348  data[i] *= weights[shift+1];
349  data[loop_length-1] *= weights[shift+2];
350  data += loop_length;
351  }
352  }
353 }
354 
355 
356 
357 template <int dim, typename Number>
358 template <int degree>
360 ::do_prolongate_add (const unsigned int to_level,
363 {
364  const unsigned int vec_size = VectorizedArray<Number>::n_array_elements;
365  const unsigned int degree_size = (degree > -1 ? degree : fe_degree) + 1;
366  const unsigned int n_child_dofs_1d = 2*degree_size - element_is_continuous;
367  const unsigned int n_scalar_cell_dofs = Utilities::fixed_power<dim>(n_child_dofs_1d);
368  const unsigned int three_to_dim = Utilities::fixed_int_power<3,dim>::value;
369 
370  for (unsigned int cell=0; cell < n_owned_level_cells[to_level-1];
371  cell += vec_size)
372  {
373  const unsigned int n_chunks = cell+vec_size > n_owned_level_cells[to_level-1] ?
374  n_owned_level_cells[to_level-1] - cell : vec_size;
375 
376  // read from source vector
377  for (unsigned int v=0; v<n_chunks; ++v)
378  {
379  const unsigned int shift = internal::MGTransfer::compute_shift_within_children<dim>
380  (parent_child_connect[to_level-1][cell+v].second,
381  fe_degree+1-element_is_continuous, fe_degree);
382  const unsigned int *indices = &level_dof_indices[to_level-1][parent_child_connect[to_level-1][cell+v].first*n_child_cell_dofs+shift];
383  for (unsigned int c=0, m=0; c<n_components; ++c)
384  {
385  for (unsigned int k=0; k<(dim>2 ? degree_size : 1); ++k)
386  for (unsigned int j=0; j<(dim>1 ? degree_size : 1); ++j)
387  for (unsigned int i=0; i<degree_size; ++i, ++m)
388  evaluation_data[m][v] =
389  src.local_element(indices[c*n_scalar_cell_dofs +
390  k*n_child_dofs_1d*n_child_dofs_1d+
391  j*n_child_dofs_1d+i]);
392 
393  // apply Dirichlet boundary conditions on parent cell
394  for (std::vector<unsigned short>::const_iterator i=dirichlet_indices[to_level-1][cell+v].begin(); i!=dirichlet_indices[to_level-1][cell+v].end(); ++i)
395  evaluation_data[*i][v] = 0.;
396  }
397  }
398 
399  AssertDimension(prolongation_matrix_1d.size(),
400  degree_size * n_child_dofs_1d);
401  // perform tensorized operation
402  if (element_is_continuous)
403  {
404  typedef internal::EvaluatorTensorProduct<internal::evaluate_general,dim,degree,degree!=-1 ? 2*degree+1 : 0,VectorizedArray<Number> > Evaluator;
405  Evaluator evaluator(prolongation_matrix_1d,
406  prolongation_matrix_1d,
407  prolongation_matrix_1d,
408  fe_degree,
409  2*fe_degree+1);
410  perform_tensorized_op<dim,Evaluator,Number,true>(evaluator,
411  n_child_cell_dofs,
412  n_components,
413  evaluation_data);
414  weight_dofs_on_child<dim,degree,Number>(&weights_on_refined[to_level-1][(cell/vec_size)*three_to_dim],
415  n_components, fe_degree,
416  &evaluation_data[2*n_child_cell_dofs]);
417  }
418  else
419  {
421  Evaluator evaluator(prolongation_matrix_1d,
422  prolongation_matrix_1d,
423  prolongation_matrix_1d,
424  fe_degree,
425  2*(fe_degree+1));
426  perform_tensorized_op<dim,Evaluator,Number,true>(evaluator,
427  n_child_cell_dofs,
428  n_components,
429  evaluation_data);
430  }
431 
432  // write into dst vector
433  const unsigned int *indices = &level_dof_indices[to_level][cell*
434  n_child_cell_dofs];
435  for (unsigned int v=0; v<n_chunks; ++v)
436  {
437  for (unsigned int i=0; i<n_child_cell_dofs; ++i)
438  dst.local_element(indices[i]) += evaluation_data[2*n_child_cell_dofs+i][v];
439  indices += n_child_cell_dofs;
440  }
441  }
442 }
443 
444 
445 
446 template <int dim, typename Number>
447 template <int degree>
449 ::do_restrict_add (const unsigned int from_level,
452 {
453  const unsigned int vec_size = VectorizedArray<Number>::n_array_elements;
454  const unsigned int degree_size = (degree > -1 ? degree : fe_degree) + 1;
455  const unsigned int n_child_dofs_1d = 2*degree_size - element_is_continuous;
456  const unsigned int n_scalar_cell_dofs = Utilities::fixed_power<dim>(n_child_dofs_1d);
457  const unsigned int three_to_dim = Utilities::fixed_int_power<3,dim>::value;
458 
459  for (unsigned int cell=0; cell < n_owned_level_cells[from_level-1];
460  cell += vec_size)
461  {
462  const unsigned int n_chunks = cell+vec_size > n_owned_level_cells[from_level-1] ?
463  n_owned_level_cells[from_level-1] - cell : vec_size;
464 
465  // read from source vector
466  {
467  const unsigned int *indices = &level_dof_indices[from_level][cell*
468  n_child_cell_dofs];
469  for (unsigned int v=0; v<n_chunks; ++v)
470  {
471  for (unsigned int i=0; i<n_child_cell_dofs; ++i)
472  evaluation_data[i][v] = src.local_element(indices[i]);
473  indices += n_child_cell_dofs;
474  }
475  }
476 
477  AssertDimension(prolongation_matrix_1d.size(),
478  degree_size * n_child_dofs_1d);
479  // perform tensorized operation
480  if (element_is_continuous)
481  {
482  typedef internal::EvaluatorTensorProduct<internal::evaluate_general,dim,degree,degree!=-1 ? 2*degree+1 : 0,VectorizedArray<Number> > Evaluator;
483  Evaluator evaluator(prolongation_matrix_1d,
484  prolongation_matrix_1d,
485  prolongation_matrix_1d,
486  fe_degree,
487  2*fe_degree+1);
488  weight_dofs_on_child<dim,degree,Number>(&weights_on_refined[from_level-1][(cell/vec_size)*three_to_dim],
489  n_components, fe_degree,
490  &evaluation_data[0]);
491  perform_tensorized_op<dim,Evaluator,Number,false>(evaluator,
492  n_child_cell_dofs,
493  n_components,
494  evaluation_data);
495  }
496  else
497  {
499  Evaluator evaluator(prolongation_matrix_1d,
500  prolongation_matrix_1d,
501  prolongation_matrix_1d,
502  fe_degree,
503  2*(fe_degree+1));
504  perform_tensorized_op<dim,Evaluator,Number,false>(evaluator,
505  n_child_cell_dofs,
506  n_components,
507  evaluation_data);
508  }
509 
510  // write into dst vector
511  for (unsigned int v=0; v<n_chunks; ++v)
512  {
513  const unsigned int shift = internal::MGTransfer::compute_shift_within_children<dim>
514  (parent_child_connect[from_level-1][cell+v].second,
515  fe_degree+1-element_is_continuous, fe_degree);
516  AssertIndexRange(parent_child_connect[from_level-1][cell+v].first*
517  n_child_cell_dofs+n_child_cell_dofs-1,
518  level_dof_indices[from_level-1].size());
519  const unsigned int *indices = &level_dof_indices[from_level-1][parent_child_connect[from_level-1][cell+v].first*n_child_cell_dofs+shift];
520  for (unsigned int c=0, m=0; c<n_components; ++c)
521  {
522  // apply Dirichlet boundary conditions on parent cell
523  for (std::vector<unsigned short>::const_iterator i=dirichlet_indices[from_level-1][cell+v].begin(); i!=dirichlet_indices[from_level-1][cell+v].end(); ++i)
524  evaluation_data[2*n_child_cell_dofs+(*i)][v] = 0.;
525 
526  for (unsigned int k=0; k<(dim>2 ? degree_size : 1); ++k)
527  for (unsigned int j=0; j<(dim>1 ? degree_size : 1); ++j)
528  for (unsigned int i=0; i<degree_size; ++i, ++m)
529  dst.local_element(indices[c*n_scalar_cell_dofs +
530  k*n_child_dofs_1d*n_child_dofs_1d+
531  j*n_child_dofs_1d+i])
532  += evaluation_data[2*n_child_cell_dofs+m][v];
533  }
534  }
535  }
536 }
537 
538 
539 
540 template <int dim, typename Number>
541 std::size_t
543 {
544  std::size_t memory = MGLevelGlobalTransfer<LinearAlgebra::distributed::Vector<Number> >::memory_consumption();
545  memory += MemoryConsumption::memory_consumption(level_dof_indices);
546  memory += MemoryConsumption::memory_consumption(parent_child_connect);
547  memory += MemoryConsumption::memory_consumption(n_owned_level_cells);
548  memory += MemoryConsumption::memory_consumption(prolongation_matrix_1d);
549  memory += MemoryConsumption::memory_consumption(evaluation_data);
550  memory += MemoryConsumption::memory_consumption(weights_on_refined);
551  memory += MemoryConsumption::memory_consumption(dirichlet_indices);
552  return memory;
553 }
554 
555 
556 // explicit instantiation
557 #include "mg_transfer_matrix_free.inst"
558 
559 
560 DEAL_II_NAMESPACE_CLOSE
static const unsigned int invalid_unsigned_int
Definition: types.h:170
void do_restrict_add(const unsigned int from_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1146
virtual void restrict_and_add(const unsigned int from_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
std::size_t memory_consumption() const
#define AssertIndexRange(index, range)
Definition: exceptions.h:1170
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
#define Assert(cond, exc)
Definition: exceptions.h:313
SmartPointer< const MGConstrainedDoFs, MGLevelGlobalTransfer< LinearAlgebra::distributed::Vector< Number > > > mg_constrained_dofs
Definition: mg_transfer.h:418
std_cxx11::enable_if< std_cxx11::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
void do_prolongate_add(const unsigned int to_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
Number local_element(const size_type local_index) const
static ::ExceptionBase & ExcNotImplemented()
virtual void prolongate(const unsigned int to_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
unsigned int n_components(const DoFHandler< dim, spacedim > &dh)
void initialize_constraints(const MGConstrainedDoFs &mg_constrained_dofs)
void build(const DoFHandler< dim, dim > &mg_dof)