Reference documentation for deal.II version GIT edc7d5c3ce 2023-09-25 07:10:03+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
mg_transfer_matrix_free.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2023 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.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 #include <deal.II/base/function.h>
18 #include <deal.II/base/logstream.h>
20 
22 #include <deal.II/dofs/dof_tools.h>
23 
24 #include <deal.II/fe/fe.h>
25 
26 #include <deal.II/grid/tria.h>
28 
30 
33 
36 #include <deal.II/multigrid/mg_transfer_matrix_free.templates.h>
37 
38 #include <algorithm>
39 
41 
42 
43 template <int dim, typename Number>
45  : fe_degree(0)
46  , element_is_continuous(false)
47  , n_components(0)
48  , n_child_cell_dofs(0)
49 {}
50 
51 
52 
53 template <int dim, typename Number>
55  const MGConstrainedDoFs &mg_c)
56  : fe_degree(0)
57  , element_is_continuous(false)
58  , n_components(0)
59  , n_child_cell_dofs(0)
60 {
61  this->mg_constrained_dofs = &mg_c;
62 }
63 
64 
65 
66 template <int dim, typename Number>
67 void
69  const MGConstrainedDoFs &mg_c)
70 {
71  this->mg_constrained_dofs = &mg_c;
72 }
73 
74 
75 
76 template <int dim, typename Number>
77 void
79 {
82  fe_degree = 0;
83  element_is_continuous = false;
84  n_components = 0;
85  n_child_cell_dofs = 0;
86  level_dof_indices.clear();
87  parent_child_connect.clear();
88  dirichlet_indices.clear();
89  n_owned_level_cells.clear();
90  prolongation_matrix_1d.clear();
91  evaluation_data.clear();
92  weights_on_refined.clear();
93 }
94 
95 
96 
97 template <int dim, typename Number>
98 void
100  const DoFHandler<dim> &dof_handler,
101  const std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
102  &external_partitioners)
103 {
104  Assert(dof_handler.has_level_dofs(),
105  ExcMessage(
106  "The underlying DoFHandler object has not had its "
107  "distribute_mg_dofs() function called, but this is a prerequisite "
108  "for multigrid transfers. You will need to call this function, "
109  "probably close to where you already call distribute_dofs()."));
110  if (external_partitioners.size() > 0)
111  {
112  Assert(this->initialize_dof_vector == nullptr,
113  ExcMessage("An initialize_dof_vector function has already "
114  "been registered in the constructor!"));
115 
116  this->initialize_dof_vector =
117  [external_partitioners](
118  const unsigned int level,
120  vec.reinit(external_partitioners[level]);
121  };
122  }
123 
124  this->fill_and_communicate_copy_indices(dof_handler);
125 
126  vector_partitioners.resize(0,
127  dof_handler.get_triangulation().n_global_levels() -
128  1);
129  for (unsigned int level = 0; level <= this->ghosted_level_vector.max_level();
130  ++level)
131  vector_partitioners[level] =
132  this->ghosted_level_vector[level].get_partitioner();
133 
134  std::vector<std::vector<Number>> weights_unvectorized;
135 
137 
138  internal::MGTransfer::setup_transfer<dim, Number>(
139  dof_handler,
140  this->mg_constrained_dofs,
141  external_partitioners,
142  elem_info,
143  level_dof_indices,
144  parent_child_connect,
145  n_owned_level_cells,
146  dirichlet_indices,
147  weights_unvectorized,
148  this->copy_indices_global_mine,
149  vector_partitioners);
150 
151  // reinit the ghosted level vector in case its partitioner differs from the
152  // one the user intends to use externally
153  this->ghosted_level_vector.resize(0, vector_partitioners.max_level());
154  for (unsigned int level = 0; level <= vector_partitioners.max_level();
155  ++level)
156  if (external_partitioners.size() == vector_partitioners.max_level() + 1 &&
157  external_partitioners[level].get() == vector_partitioners[level].get())
158  this->ghosted_level_vector[level].reinit(0);
159  else
160  this->ghosted_level_vector[level].reinit(vector_partitioners[level]);
161 
162  // unpack element info data
163  fe_degree = elem_info.fe_degree;
164  element_is_continuous = elem_info.element_is_continuous;
165  n_components = elem_info.n_components;
166  n_child_cell_dofs = elem_info.n_child_cell_dofs;
167 
168  // duplicate and put into vectorized array
169  prolongation_matrix_1d.resize(elem_info.prolongation_matrix_1d.size());
170  for (unsigned int i = 0; i < elem_info.prolongation_matrix_1d.size(); ++i)
171  prolongation_matrix_1d[i] = elem_info.prolongation_matrix_1d[i];
172 
173  // reshuffle into aligned vector of vectorized arrays
174  const unsigned int vec_size = VectorizedArray<Number>::size();
175  const unsigned int n_levels =
176  dof_handler.get_triangulation().n_global_levels();
177 
178  const unsigned int n_weights_per_cell = Utilities::fixed_power<dim>(3);
179  weights_on_refined.resize(n_levels - 1);
180  for (unsigned int level = 1; level < n_levels; ++level)
181  {
182  weights_on_refined[level - 1].resize(
183  ((n_owned_level_cells[level - 1] + vec_size - 1) / vec_size) *
184  n_weights_per_cell);
185 
186  for (unsigned int c = 0; c < n_owned_level_cells[level - 1]; ++c)
187  {
188  const unsigned int comp = c / vec_size;
189  const unsigned int v = c % vec_size;
190  for (unsigned int i = 0; i < n_weights_per_cell; ++i)
191  {
192  weights_on_refined[level - 1][comp * n_weights_per_cell + i][v] =
193  weights_unvectorized[level - 1][c * n_weights_per_cell + i];
194  }
195  }
196  }
197 
198  evaluation_data.resize(n_child_cell_dofs);
199 }
200 
201 
202 
203 template <int dim, typename Number>
204 void
206  const DoFHandler<dim> &dof_handler,
207  const std::function<void(const unsigned int,
209  &initialize_dof_vector)
210 {
211  if (initialize_dof_vector)
212  {
213  const unsigned int n_levels =
214  dof_handler.get_triangulation().n_global_levels();
215 
216  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
217  external_partitioners(n_levels);
218 
219  for (unsigned int level = 0; level < n_levels; ++level)
220  {
222  initialize_dof_vector(level, vector);
223  external_partitioners[level] = vector.get_partitioner();
224  }
225 
226  build(dof_handler, external_partitioners);
227  }
228  else
229  {
230  build(dof_handler);
231  }
232 }
233 
234 
235 
236 template <int dim, typename Number>
237 void
239  const unsigned int to_level,
242 {
243  dst = 0;
244  prolongate_and_add(to_level, dst, src);
245 }
246 
247 
248 
249 template <int dim, typename Number>
250 void
252  const unsigned int to_level,
255 {
256  Assert((to_level >= 1) && (to_level <= level_dof_indices.size()),
257  ExcIndexRange(to_level, 1, level_dof_indices.size() + 1));
258 
259  const bool src_inplace = src.get_partitioner().get() ==
260  this->vector_partitioners[to_level - 1].get();
261  if (src_inplace == false)
262  {
263  if (this->ghosted_level_vector[to_level - 1].get_partitioner().get() !=
264  this->vector_partitioners[to_level - 1].get())
265  this->ghosted_level_vector[to_level - 1].reinit(
266  this->vector_partitioners[to_level - 1]);
267  this->ghosted_level_vector[to_level - 1].copy_locally_owned_data_from(
268  src);
269  }
270 
271  const bool dst_inplace =
272  dst.get_partitioner().get() == this->vector_partitioners[to_level].get();
273  if (dst_inplace == false)
274  {
275  if (this->ghosted_level_vector[to_level].get_partitioner().get() !=
276  this->vector_partitioners[to_level].get())
277  this->ghosted_level_vector[to_level].reinit(
278  this->vector_partitioners[to_level]);
279  AssertDimension(this->ghosted_level_vector[to_level].locally_owned_size(),
280  dst.locally_owned_size());
281  this->ghosted_level_vector[to_level] = 0.;
282  }
283 
285  src_inplace ? src : this->ghosted_level_vector[to_level - 1];
287  dst_inplace ? dst : this->ghosted_level_vector[to_level];
288 
289  src_vec.update_ghost_values();
290  // the implementation in do_prolongate_add is templated in the degree of the
291  // element (for efficiency reasons), so we need to find the appropriate
292  // kernel here...
293  if (fe_degree == 0)
294  do_prolongate_add<0>(to_level, dst_vec, src_vec);
295  else if (fe_degree == 1)
296  do_prolongate_add<1>(to_level, dst_vec, src_vec);
297  else if (fe_degree == 2)
298  do_prolongate_add<2>(to_level, dst_vec, src_vec);
299  else if (fe_degree == 3)
300  do_prolongate_add<3>(to_level, dst_vec, src_vec);
301  else if (fe_degree == 4)
302  do_prolongate_add<4>(to_level, dst_vec, src_vec);
303  else if (fe_degree == 5)
304  do_prolongate_add<5>(to_level, dst_vec, src_vec);
305  else if (fe_degree == 6)
306  do_prolongate_add<6>(to_level, dst_vec, src_vec);
307  else if (fe_degree == 7)
308  do_prolongate_add<7>(to_level, dst_vec, src_vec);
309  else if (fe_degree == 8)
310  do_prolongate_add<8>(to_level, dst_vec, src_vec);
311  else if (fe_degree == 9)
312  do_prolongate_add<9>(to_level, dst_vec, src_vec);
313  else if (fe_degree == 10)
314  do_prolongate_add<10>(to_level, dst_vec, src_vec);
315  else
316  do_prolongate_add<-1>(to_level, dst_vec, src_vec);
317 
319  if (dst_inplace == false)
320  dst += dst_vec;
321 
322  if (src_inplace == true)
323  src.zero_out_ghost_values();
324 }
325 
326 
327 
328 template <int dim, typename Number>
329 void
331  const unsigned int from_level,
334 {
335  Assert((from_level >= 1) && (from_level <= level_dof_indices.size()),
336  ExcIndexRange(from_level, 1, level_dof_indices.size() + 1));
337 
338  const bool src_inplace =
339  src.get_partitioner().get() == this->vector_partitioners[from_level].get();
340  if (src_inplace == false)
341  {
342  if (this->ghosted_level_vector[from_level].get_partitioner().get() !=
343  this->vector_partitioners[from_level].get())
344  this->ghosted_level_vector[from_level].reinit(
345  this->vector_partitioners[from_level]);
346  this->ghosted_level_vector[from_level].copy_locally_owned_data_from(src);
347  }
348 
349  const bool dst_inplace = dst.get_partitioner().get() ==
350  this->vector_partitioners[from_level - 1].get();
351  if (dst_inplace == false)
352  {
353  if (this->ghosted_level_vector[from_level - 1].get_partitioner().get() !=
354  this->vector_partitioners[from_level - 1].get())
355  this->ghosted_level_vector[from_level - 1].reinit(
356  this->vector_partitioners[from_level - 1]);
358  this->ghosted_level_vector[from_level - 1].locally_owned_size(),
359  dst.locally_owned_size());
360  this->ghosted_level_vector[from_level - 1] = 0.;
361  }
362 
364  src_inplace ? src : this->ghosted_level_vector[from_level];
366  dst_inplace ? dst : this->ghosted_level_vector[from_level - 1];
367 
368  src_vec.update_ghost_values();
369 
370  if (fe_degree == 0)
371  do_restrict_add<0>(from_level, dst_vec, src_vec);
372  else if (fe_degree == 1)
373  do_restrict_add<1>(from_level, dst_vec, src_vec);
374  else if (fe_degree == 2)
375  do_restrict_add<2>(from_level, dst_vec, src_vec);
376  else if (fe_degree == 3)
377  do_restrict_add<3>(from_level, dst_vec, src_vec);
378  else if (fe_degree == 4)
379  do_restrict_add<4>(from_level, dst_vec, src_vec);
380  else if (fe_degree == 5)
381  do_restrict_add<5>(from_level, dst_vec, src_vec);
382  else if (fe_degree == 6)
383  do_restrict_add<6>(from_level, dst_vec, src_vec);
384  else if (fe_degree == 7)
385  do_restrict_add<7>(from_level, dst_vec, src_vec);
386  else if (fe_degree == 8)
387  do_restrict_add<8>(from_level, dst_vec, src_vec);
388  else if (fe_degree == 9)
389  do_restrict_add<9>(from_level, dst_vec, src_vec);
390  else if (fe_degree == 10)
391  do_restrict_add<10>(from_level, dst_vec, src_vec);
392  else
393  // go to the non-templated version of the evaluator
394  do_restrict_add<-1>(from_level, dst_vec, src_vec);
395 
397  if (dst_inplace == false)
398  dst += dst_vec;
399 
400  if (src_inplace == true)
401  src.zero_out_ghost_values();
402 }
403 
404 
405 
406 template <int dim, typename Number>
407 template <int degree>
408 void
410  const unsigned int to_level,
413 {
414  const unsigned int vec_size = VectorizedArray<Number>::size();
415  const unsigned int degree_size = (degree > -1 ? degree : fe_degree) + 1;
416  const unsigned int n_child_dofs_1d = 2 * degree_size - element_is_continuous;
417  const unsigned int n_scalar_cell_dofs =
418  Utilities::fixed_power<dim>(n_child_dofs_1d);
419  constexpr unsigned int three_to_dim = Utilities::pow(3, dim);
420 
421  // If we have user defined MG constraints, we must create
422  // a non-const, ghosted version of the source vector to distribute
423  // constraints.
424  const LinearAlgebra::distributed::Vector<Number> *to_use = &src;
426  if (this->mg_constrained_dofs != nullptr &&
427  this->mg_constrained_dofs->get_user_constraint_matrix(to_level - 1)
428  .get_local_lines()
429  .size() > 0)
430  {
432 
433  // Distribute any user defined constraints
434  this->mg_constrained_dofs->get_user_constraint_matrix(to_level - 1)
435  .distribute(copy_src);
436 
437  // Re-initialize new ghosted vector with correct constraints
438  new_src.reinit(copy_src);
439  new_src = copy_src;
440  new_src.update_ghost_values();
441 
442  to_use = &new_src;
443  }
444 
445  for (unsigned int cell = 0; cell < n_owned_level_cells[to_level - 1];
446  cell += vec_size)
447  {
448  const unsigned int n_lanes =
449  (cell + vec_size > n_owned_level_cells[to_level - 1]) ?
450  (n_owned_level_cells[to_level - 1] - cell) :
451  vec_size;
452 
453  // read from source vector
454  for (unsigned int v = 0; v < n_lanes; ++v)
455  {
456  const unsigned int shift =
457  internal::MGTransfer::compute_shift_within_children<dim>(
458  parent_child_connect[to_level - 1][cell + v].second,
459  fe_degree + 1 - element_is_continuous,
460  fe_degree);
461  const unsigned int *indices =
462  &level_dof_indices[to_level - 1]
463  [parent_child_connect[to_level - 1][cell + v]
464  .first *
465  n_child_cell_dofs +
466  shift];
467  for (unsigned int c = 0, m = 0; c < n_components; ++c)
468  {
469  for (unsigned int k = 0; k < (dim > 2 ? degree_size : 1); ++k)
470  for (unsigned int j = 0; j < (dim > 1 ? degree_size : 1); ++j)
471  for (unsigned int i = 0; i < degree_size; ++i, ++m)
472  evaluation_data[m][v] = to_use->local_element(
473  indices[c * n_scalar_cell_dofs +
474  k * n_child_dofs_1d * n_child_dofs_1d +
475  j * n_child_dofs_1d + i]);
476 
477  // apply Dirichlet boundary conditions on parent cell
478  for (std::vector<unsigned short>::const_iterator i =
479  dirichlet_indices[to_level - 1][cell + v].begin();
480  i != dirichlet_indices[to_level - 1][cell + v].end();
481  ++i)
482  evaluation_data[*i][v] = 0.;
483  }
484  }
485 
486  AssertDimension(prolongation_matrix_1d.size(),
487  degree_size * n_child_dofs_1d);
488  // perform tensorized operation
489  if (element_is_continuous)
490  {
491  // must go through the components backwards because we want to write
492  // the output to the same array as the input
493  for (int c = n_components - 1; c >= 0; --c)
497  dim,
498  degree + 1,
499  2 * degree + 1>::do_forward(1,
500  prolongation_matrix_1d,
501  evaluation_data.begin() +
502  c * Utilities::fixed_power<dim>(
503  degree_size),
504  evaluation_data.begin() +
505  c * n_scalar_cell_dofs,
506  fe_degree + 1,
507  2 * fe_degree + 1);
509  degree != -1 ? 2 * degree + 1 :
510  -1,
512  &weights_on_refined[to_level - 1][(cell / vec_size) * three_to_dim],
513  n_components,
514  2 * fe_degree + 1,
515  evaluation_data.begin());
516  }
517  else
518  {
519  for (int c = n_components - 1; c >= 0; --c)
523  dim,
524  degree + 1,
525  2 * degree + 2>::do_forward(1,
526  prolongation_matrix_1d,
527  evaluation_data.begin() +
528  c * Utilities::fixed_power<dim>(
529  degree_size),
530  evaluation_data.begin() +
531  c * n_scalar_cell_dofs,
532  fe_degree + 1,
533  2 * fe_degree + 2);
534  }
535 
536  // write into dst vector
537  const unsigned int *indices =
538  &level_dof_indices[to_level][cell * n_child_cell_dofs];
539  for (unsigned int v = 0; v < n_lanes; ++v)
540  {
541  for (unsigned int i = 0; i < n_child_cell_dofs; ++i)
542  dst.local_element(indices[i]) += evaluation_data[i][v];
543  indices += n_child_cell_dofs;
544  }
545  }
546 }
547 
548 
549 
550 template <int dim, typename Number>
551 template <int degree>
552 void
554  const unsigned int from_level,
557 {
558  const unsigned int vec_size = VectorizedArray<Number>::size();
559  const unsigned int degree_size = (degree > -1 ? degree : fe_degree) + 1;
560  const unsigned int n_child_dofs_1d = 2 * degree_size - element_is_continuous;
561  const unsigned int n_scalar_cell_dofs =
562  Utilities::fixed_power<dim>(n_child_dofs_1d);
563  constexpr unsigned int three_to_dim = Utilities::pow(3, dim);
564 
565  for (unsigned int cell = 0; cell < n_owned_level_cells[from_level - 1];
566  cell += vec_size)
567  {
568  const unsigned int n_lanes =
569  (cell + vec_size > n_owned_level_cells[from_level - 1]) ?
570  (n_owned_level_cells[from_level - 1] - cell) :
571  vec_size;
572 
573  // read from source vector
574  {
575  const unsigned int *indices =
576  &level_dof_indices[from_level][cell * n_child_cell_dofs];
577  for (unsigned int v = 0; v < n_lanes; ++v)
578  {
579  for (unsigned int i = 0; i < n_child_cell_dofs; ++i)
580  evaluation_data[i][v] = src.local_element(indices[i]);
581  indices += n_child_cell_dofs;
582  }
583  }
584 
585  AssertDimension(prolongation_matrix_1d.size(),
586  degree_size * n_child_dofs_1d);
587  // perform tensorized operation
588  if (element_is_continuous)
589  {
591  degree != -1 ? 2 * degree + 1 :
592  -1,
594  &weights_on_refined[from_level - 1]
595  [(cell / vec_size) * three_to_dim],
596  n_components,
597  2 * fe_degree + 1,
598  evaluation_data.data());
599  for (unsigned int c = 0; c < n_components; ++c)
603  dim,
604  degree + 1,
605  2 * degree + 1>::do_backward(1,
606  prolongation_matrix_1d,
607  false,
608  evaluation_data.begin() +
609  c * n_scalar_cell_dofs,
610  evaluation_data.begin() +
611  c * Utilities::fixed_power<dim>(
612  degree_size),
613  fe_degree + 1,
614  2 * fe_degree + 1);
615  }
616  else
617  {
618  for (unsigned int c = 0; c < n_components; ++c)
622  dim,
623  degree + 1,
624  2 * degree + 2>::do_backward(1,
625  prolongation_matrix_1d,
626  false,
627  evaluation_data.begin() +
628  c * n_scalar_cell_dofs,
629  evaluation_data.begin() +
630  c * Utilities::fixed_power<dim>(
631  degree_size),
632  fe_degree + 1,
633  2 * fe_degree + 2);
634  }
635 
636  // write into dst vector
637  for (unsigned int v = 0; v < n_lanes; ++v)
638  {
639  const unsigned int shift =
640  internal::MGTransfer::compute_shift_within_children<dim>(
641  parent_child_connect[from_level - 1][cell + v].second,
642  fe_degree + 1 - element_is_continuous,
643  fe_degree);
645  parent_child_connect[from_level - 1][cell + v].first *
646  n_child_cell_dofs +
647  n_child_cell_dofs - 1,
648  level_dof_indices[from_level - 1].size());
649  const unsigned int *indices =
650  &level_dof_indices[from_level - 1]
651  [parent_child_connect[from_level - 1][cell + v]
652  .first *
653  n_child_cell_dofs +
654  shift];
655  for (unsigned int c = 0, m = 0; c < n_components; ++c)
656  {
657  // apply Dirichlet boundary conditions on parent cell
658  for (std::vector<unsigned short>::const_iterator i =
659  dirichlet_indices[from_level - 1][cell + v].begin();
660  i != dirichlet_indices[from_level - 1][cell + v].end();
661  ++i)
662  evaluation_data[*i][v] = 0.;
663 
664  for (unsigned int k = 0; k < (dim > 2 ? degree_size : 1); ++k)
665  for (unsigned int j = 0; j < (dim > 1 ? degree_size : 1); ++j)
666  for (unsigned int i = 0; i < degree_size; ++i, ++m)
667  dst.local_element(
668  indices[c * n_scalar_cell_dofs +
669  k * n_child_dofs_1d * n_child_dofs_1d +
670  j * n_child_dofs_1d + i]) +=
671  evaluation_data[m][v];
672  }
673  }
674  }
675 }
676 
677 
678 
679 template <int dim, typename Number>
680 std::size_t
682 {
683  std::size_t memory = MGLevelGlobalTransfer<
685  memory += MemoryConsumption::memory_consumption(level_dof_indices);
686  memory += MemoryConsumption::memory_consumption(parent_child_connect);
687  memory += MemoryConsumption::memory_consumption(n_owned_level_cells);
688  memory += MemoryConsumption::memory_consumption(prolongation_matrix_1d);
689  memory += MemoryConsumption::memory_consumption(evaluation_data);
690  memory += MemoryConsumption::memory_consumption(weights_on_refined);
691  memory += MemoryConsumption::memory_consumption(dirichlet_indices);
692  return memory;
693 }
694 
695 
696 
697 template <int dim, typename Number>
699  const MGConstrainedDoFs &mg_c)
701  Number,
702  MGTransferMatrixFree<dim, Number>>(true)
703 {
704  this->matrix_free_transfer_vector.emplace_back(mg_c);
705 }
706 
707 
708 
709 template <int dim, typename Number>
711  const std::vector<MGConstrainedDoFs> &mg_c)
713  Number,
714  MGTransferMatrixFree<dim, Number>>(false)
715 {
716  for (const auto &constrained_block_dofs : mg_c)
717  this->matrix_free_transfer_vector.emplace_back(constrained_block_dofs);
718 }
719 
720 
721 
722 template <int dim, typename Number>
723 void
725  const MGConstrainedDoFs &mg_c)
726 {
727  Assert(this->same_for_all,
728  ExcMessage("This object was initialized with support for usage with "
729  "one DoFHandler for each block, but this method assumes "
730  "that the same DoFHandler is used for all the blocks!"));
731  AssertDimension(this->matrix_free_transfer_vector.size(), 1);
732 
733  this->matrix_free_transfer_vector[0].initialize_constraints(mg_c);
734 }
735 
736 
737 
738 template <int dim, typename Number>
739 void
741  const std::vector<MGConstrainedDoFs> &mg_c)
742 {
743  Assert(!this->same_for_all,
744  ExcMessage("This object was initialized with support for using "
745  "the same DoFHandler for all the blocks, but this "
746  "method assumes that there is a separate DoFHandler "
747  "for each block!"));
748  AssertDimension(this->matrix_free_transfer_vector.size(), mg_c.size());
749 
750  for (unsigned int i = 0; i < mg_c.size(); ++i)
751  this->matrix_free_transfer_vector[i].initialize_constraints(mg_c[i]);
752 }
753 
754 
755 
756 template <int dim, typename Number>
757 void
759  const DoFHandler<dim> &dof_handler)
760 {
761  AssertDimension(this->matrix_free_transfer_vector.size(), 1);
762  this->matrix_free_transfer_vector[0].build(dof_handler);
763 }
764 
765 
766 
767 template <int dim, typename Number>
768 void
770  const std::vector<const DoFHandler<dim> *> &dof_handler)
771 {
772  AssertDimension(this->matrix_free_transfer_vector.size(), dof_handler.size());
773  for (unsigned int i = 0; i < dof_handler.size(); ++i)
774  this->matrix_free_transfer_vector[i].build(*dof_handler[i]);
775 }
776 
777 
778 
779 template <int dim, typename Number>
780 std::size_t
782 {
783  std::size_t total_memory_consumption = 0;
784  for (const auto &el : this->matrix_free_transfer_vector)
785  total_memory_consumption += el.memory_consumption();
786  return total_memory_consumption;
787 }
788 
789 
790 
791 template <int dim, typename Number>
794  const unsigned int b) const
795 {
796  return matrix_free_transfer_vector[b];
797 }
798 
799 
800 
801 template <int dim, typename Number>
802 void
804 {
805  this->matrix_free_transfer_vector.clear();
806 }
807 
808 
809 
810 // explicit instantiation
811 #include "mg_transfer_matrix_free.inst"
812 
813 
const Triangulation< dim, spacedim > & get_triangulation() const
bool has_level_dofs() const
Number local_element(const size_type local_index) const
size_type locally_owned_size() const
const std::shared_ptr< const Utilities::MPI::Partitioner > & get_partitioner() const
void compress(VectorOperation::values operation)
void reinit(const size_type size, const bool omit_zeroing_entries=false)
std::vector< MGTransferMatrixFree< dim, Number > > matrix_free_transfer_vector
void build(const DoFHandler< dim > &dof_handler)
std::size_t memory_consumption() const
MGTransferBlockMatrixFree()=default
const MGTransferMatrixFree< dim, Number > & get_matrix_free_transfer(const unsigned int b) const override
void initialize_constraints(const MGConstrainedDoFs &mg_constrained_dofs)
void do_restrict_add(const unsigned int from_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
void do_prolongate_add(const unsigned int to_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const
virtual void prolongate(const unsigned int to_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const override
void initialize_constraints(const MGConstrainedDoFs &mg_constrained_dofs)
void build(const DoFHandler< dim > &dof_handler, const std::vector< std::shared_ptr< const Utilities::MPI::Partitioner >> &external_partitioners=std::vector< std::shared_ptr< const Utilities::MPI::Partitioner >>())
virtual void prolongate_and_add(const unsigned int to_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const override
std::size_t memory_consumption() const
virtual void restrict_and_add(const unsigned int from_level, LinearAlgebra::distributed::Vector< Number > &dst, const LinearAlgebra::distributed::Vector< Number > &src) const override
virtual unsigned int n_global_levels() const
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:477
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:478
Point< 2 > second
Definition: grid_out.cc:4615
Point< 2 > first
Definition: grid_out.cc:4614
unsigned int level
Definition: grid_out.cc:4617
#define Assert(cond, exc)
Definition: exceptions.h:1616
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1789
#define AssertIndexRange(index, range)
Definition: exceptions.h:1857
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcMessage(std::string arg1)
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2132
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
VectorType::value_type * begin(VectorType &V)
constexpr T pow(const T base, const int iexp)
Definition: utilities.h:447
void weight_fe_q_dofs_by_entity(const Number *weights, const unsigned int n_components, const int n_points_1d_non_template, Number *data)
std::vector< Number > prolongation_matrix_1d