1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2020 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 #ifndef dealii_mg_transfer_global_coarsening_templates_h
18 #define dealii_mg_transfer_global_coarsening_templates_h
19 
20 #include <deal.II/base/config.h>
21 
22 #include <deal.II/base/mpi_compute_index_owner_internal.h>
23 #include <deal.II/base/mpi_consensus_algorithms.h>
24 
25 #include <deal.II/dofs/dof_handler.h>
26 #include <deal.II/dofs/dof_tools.h>
27 
28 #include <deal.II/fe/fe_tools.h>
29 
30 #include <deal.II/hp/dof_handler.h>
31 
32 #include <deal.II/matrix_free/evaluation_kernels.h>
33 #include <deal.II/matrix_free/fe_evaluation.h>
34 
35 #include <deal.II/multigrid/mg_transfer_global_coarsening.h>
36 
37 DEAL_II_NAMESPACE_OPEN
38 
39 namespace
40 {
41   /**
42    * Helper class to select the right templated implementation.
43    *
44    * @note This class is similar to internal::FEEvaluationFactory
45    */
46   class CellTransferFactory
47   {
48   public:
49     static const unsigned int max_degree = 9;
50 
CellTransferFactory(const unsigned int degree_fine,const unsigned int degree_coarse)51     CellTransferFactory(const unsigned int degree_fine,
52                         const unsigned int degree_coarse)
53       : degree_fine(degree_fine)
54       , degree_coarse(degree_coarse)
55     {}
56 
57     template <typename Fu, unsigned int deg = 1>
58     bool
run(Fu & fu)59     run(Fu &fu)
60     {
61       if ((degree_fine == (2 * deg + 1)) && (degree_coarse == deg))
62         fu.template run<2 * deg + 1, deg>(); // h-MG
63       else if ((degree_fine == deg) && (degree_coarse == std::max(deg / 2, 1u)))
64         fu.template run<deg, std::max(deg / 2u, 1u)>(); // p-MG: bisection
65       else if ((degree_fine == deg) && (degree_coarse == deg))
66         fu.template run<deg, deg>(); // identity (nothing to do)
67       else if ((degree_fine == deg) && (degree_coarse == std::max(deg - 1, 1u)))
68         fu.template run<deg, std::max(deg - 1u, 1u)>(); // p-MG: --
69       else if ((degree_fine == deg) && (degree_coarse == 1))
70         fu.template run<deg, 1>(); // p-MG: jump to 1
71       else if (deg < max_degree)
72         return run<Fu, std::min(deg + 1, max_degree)>(fu); // try next degree
73       else
74         {
75           // no match -> slow path
76           fu.template run<-1, -1>(degree_fine, degree_coarse);
77           return false; // indicate that slow path has been taken
78         }
79 
80       return true; // indicate that fast path has been taken
81     }
82 
83   private:
84     const unsigned int degree_fine;
85     const unsigned int degree_coarse;
86   };
87 
88   /**
89    * Helper class containing the cell-wise prolongation operation.
90    */
91   template <int dim, typename Number>
92   class CellProlongator
93   {
94   public:
CellProlongator(const AlignedVector<Number> & prolongation_matrix_1d,const Number * evaluation_data_coarse,Number * evaluation_data_fine)95     CellProlongator(const AlignedVector<Number> &prolongation_matrix_1d,
96                     const Number *               evaluation_data_coarse,
97                     Number *                     evaluation_data_fine)
98       : prolongation_matrix_1d(prolongation_matrix_1d)
99       , evaluation_data_coarse(evaluation_data_coarse)
100       , evaluation_data_fine(evaluation_data_fine)
101     {}
102 
103     template <int degree_fine, int degree_coarse>
104     void
105     run(const unsigned int degree_fine_   = numbers::invalid_unsigned_int,
106         const unsigned int degree_coarse_ = numbers::invalid_unsigned_int)
107     {
108       internal::FEEvaluationImplBasisChange<
109         internal::evaluate_general,
110         internal::EvaluatorQuantity::value,
111         dim,
112         degree_coarse + 1,
113         degree_fine + 1,
114         Number,
115         Number>::do_forward(1,
116                             prolongation_matrix_1d,
117                             evaluation_data_coarse,
118                             evaluation_data_fine,
119                             degree_coarse_ + 1,
120                             degree_fine_ + 1);
121     }
122 
123   private:
124     const AlignedVector<Number> &prolongation_matrix_1d;
125     const Number *               evaluation_data_coarse;
126     Number *                     evaluation_data_fine;
127   };
128 
129   /**
130    * Helper class containing the cell-wise restriction operation.
131    */
132   template <int dim, typename Number>
133   class CellRestrictor
134   {
135   public:
CellRestrictor(const AlignedVector<Number> & prolongation_matrix_1d,Number * evaluation_data_fine,Number * evaluation_data_coarse)136     CellRestrictor(const AlignedVector<Number> &prolongation_matrix_1d,
137                    Number *                     evaluation_data_fine,
138                    Number *                     evaluation_data_coarse)
139       : prolongation_matrix_1d(prolongation_matrix_1d)
140       , evaluation_data_fine(evaluation_data_fine)
141       , evaluation_data_coarse(evaluation_data_coarse)
142     {}
143 
144     template <int degree_fine, int degree_coarse>
145     void
146     run(const unsigned int degree_fine_   = numbers::invalid_unsigned_int,
147         const unsigned int degree_coarse_ = numbers::invalid_unsigned_int)
148     {
149       internal::FEEvaluationImplBasisChange<
150         internal::evaluate_general,
151         internal::EvaluatorQuantity::value,
152         dim,
153         degree_coarse == 0 ? -1 : (degree_coarse + 1),
154         degree_fine == 0 ? -1 : (degree_fine + 1),
155         Number,
156         Number>::do_backward(1,
157                              prolongation_matrix_1d,
158                              false,
159                              evaluation_data_fine,
160                              evaluation_data_coarse,
161                              degree_coarse_ + 1,
162                              degree_fine_ + 1);
163     }
164 
165   private:
166     const AlignedVector<Number> &prolongation_matrix_1d;
167     Number *                     evaluation_data_fine;
168     Number *                     evaluation_data_coarse;
169   };
170 
171   class CellProlongatorTest
172   {
173   public:
174     template <int degree_fine, int degree_coarse>
175     void
176     run(const unsigned int = numbers::invalid_unsigned_int,
177         const unsigned int = numbers::invalid_unsigned_int)
178     {}
179   };
180 
181 } // namespace
182 
183 
184 
185 namespace internal
186 {
187   namespace
188   {
189     template <typename MeshType>
190     MPI_Comm
get_mpi_comm(const MeshType & mesh)191     get_mpi_comm(const MeshType &mesh)
192     {
193       const auto *tria_parallel = dynamic_cast<
194         const dealii::parallel::TriangulationBase<MeshType::dimension,
195                                                   MeshType::space_dimension> *>(
196         &(mesh.get_triangulation()));
197 
198       return tria_parallel != nullptr ? tria_parallel->get_communicator() :
199                                         MPI_COMM_SELF;
200     }
201 
202     template <int dim>
203     unsigned int
compute_shift_within_children(const unsigned int child,const unsigned int fe_shift_1d,const unsigned int fe_degree)204     compute_shift_within_children(const unsigned int child,
205                                   const unsigned int fe_shift_1d,
206                                   const unsigned int fe_degree)
207     {
208       // we put the degrees of freedom of all child cells in lexicographic
209       // ordering
210       unsigned int c_tensor_index[dim];
211       unsigned int tmp = child;
212       for (unsigned int d = 0; d < dim; ++d)
213         {
214           c_tensor_index[d] = tmp % 2;
215           tmp /= 2;
216         }
217       const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
218       unsigned int       factor          = 1;
219       unsigned int       shift           = fe_shift_1d * c_tensor_index[0];
220       for (unsigned int d = 1; d < dim; ++d)
221         {
222           factor *= n_child_dofs_1d;
223           shift = shift + factor * fe_shift_1d * c_tensor_index[d];
224         }
225       return shift;
226     }
227 
228     template <int dim>
229     void
get_child_offset(const unsigned int child,const unsigned int fe_shift_1d,const unsigned int fe_degree,std::vector<unsigned int> & local_dof_indices)230     get_child_offset(const unsigned int         child,
231                      const unsigned int         fe_shift_1d,
232                      const unsigned int         fe_degree,
233                      std::vector<unsigned int> &local_dof_indices)
234     {
235       const unsigned int n_child_dofs_1d = fe_degree + 1 + fe_shift_1d;
236       const unsigned int shift =
237         compute_shift_within_children<dim>(child, fe_shift_1d, fe_degree);
238       const unsigned int n_components =
239         local_dof_indices.size() / Utilities::fixed_power<dim>(fe_degree + 1);
240       const unsigned int n_scalar_cell_dofs =
241         Utilities::fixed_power<dim>(n_child_dofs_1d);
242       for (unsigned int c = 0, m = 0; c < n_components; ++c)
243         for (unsigned int k = 0; k < (dim > 2 ? (fe_degree + 1) : 1); ++k)
244           for (unsigned int j = 0; j < (dim > 1 ? (fe_degree + 1) : 1); ++j)
245             for (unsigned int i = 0; i < (fe_degree + 1); ++i, ++m)
246               local_dof_indices[m] = c * n_scalar_cell_dofs +
247                                      k * n_child_dofs_1d * n_child_dofs_1d +
248                                      j * n_child_dofs_1d + i + shift;
249     }
250 
251     template <int dim>
252     std::vector<std::vector<unsigned int>>
get_child_offsets(const unsigned int dofs_per_cell_coarse,const unsigned int fe_shift_1d,const unsigned int fe_degree)253     get_child_offsets(const unsigned int dofs_per_cell_coarse,
254                       const unsigned int fe_shift_1d,
255                       const unsigned int fe_degree)
256     {
257       std::vector<std::vector<unsigned int>> cell_local_chilren_indices(
258         GeometryInfo<dim>::max_children_per_cell,
259         std::vector<unsigned int>(dofs_per_cell_coarse));
260       {
261         for (unsigned int c = 0; c < GeometryInfo<dim>::max_children_per_cell;
262              c++)
263           get_child_offset<dim>(c,
264                                 fe_shift_1d,
265                                 fe_degree,
266                                 cell_local_chilren_indices[c]);
267       }
268       return cell_local_chilren_indices;
269     }
270 
271     template <int dim>
272     types::coarse_cell_id
convert_cell_id_binary_type_to_level_coarse_cell_id(const typename CellId::binary_type & binary_representation)273     convert_cell_id_binary_type_to_level_coarse_cell_id(
274       const typename CellId::binary_type &binary_representation)
275     {
276       // exploiting the structure of CellId::binary_type
277       // see also the documentation of CellId
278 
279       // actual coarse-grid id
280       const unsigned int coarse_cell_id  = binary_representation[0];
281       const unsigned int n_child_indices = binary_representation[1] >> 2;
282 
283       const unsigned int children_per_value =
284         sizeof(CellId::binary_type::value_type) * 8 / dim;
285       unsigned int child_level  = 0;
286       unsigned int binary_entry = 2;
287 
288       // path to the get to the cell
289       std::vector<unsigned int> cell_indices;
290       while (child_level < n_child_indices)
291         {
292           Assert(binary_entry < binary_representation.size(),
293                  ExcInternalError());
294 
295           for (unsigned int j = 0; j < children_per_value; ++j)
296             {
297               unsigned int cell_index =
298                 (((binary_representation[binary_entry] >> (j * dim))) &
299                  (GeometryInfo<dim>::max_children_per_cell - 1));
300               cell_indices.push_back(cell_index);
301               ++child_level;
302               if (child_level == n_child_indices)
303                 break;
304             }
305           ++binary_entry;
306         }
307 
308       // compute new coarse-grid id: c_{i+1} = c_{i}*2^dim + q;
309       types::coarse_cell_id level_coarse_cell_id = coarse_cell_id;
310       for (auto i : cell_indices)
311         level_coarse_cell_id =
312           level_coarse_cell_id * GeometryInfo<dim>::max_children_per_cell + i;
313 
314       return level_coarse_cell_id;
315     }
316 
317   } // namespace
318 
319   class FineDoFHandlerViewCell
320   {
321   public:
FineDoFHandlerViewCell(const std::function<bool ()> & has_children_function,const std::function<void (std::vector<types::global_dof_index> &)> & get_dof_indices_function)322     FineDoFHandlerViewCell(
323       const std::function<bool()> &has_children_function,
324       const std::function<void(std::vector<types::global_dof_index> &)>
325         &get_dof_indices_function)
326       : has_children_function(has_children_function)
327       , get_dof_indices_function(get_dof_indices_function)
328     {}
329 
330     bool
has_children()331     has_children() const
332     {
333       return has_children_function();
334     }
335 
336     void
get_dof_indices(std::vector<types::global_dof_index> & dof_indices)337     get_dof_indices(std::vector<types::global_dof_index> &dof_indices) const
338     {
339       get_dof_indices_function(dof_indices);
340     }
341 
342 
343   private:
344     const std::function<bool()> has_children_function;
345     const std::function<void(std::vector<types::global_dof_index> &)>
346       get_dof_indices_function;
347   };
348 
349   template <int dim>
350   class CellIDTranslator
351   {
352   public:
CellIDTranslator(const unsigned int n_coarse_cells,const unsigned int n_global_levels)353     CellIDTranslator(const unsigned int n_coarse_cells,
354                      const unsigned int n_global_levels)
355       : n_coarse_cells(n_coarse_cells)
356       , n_global_levels(n_global_levels)
357     {
358       tree_sizes.push_back(0);
359       for (unsigned int i = 0; i < n_global_levels; ++i)
360         tree_sizes.push_back(
361           tree_sizes.back() +
362           Utilities::pow(GeometryInfo<dim>::max_children_per_cell, i) *
363             n_coarse_cells);
364     }
365 
366     unsigned int
size()367     size() const
368     {
369       return n_coarse_cells *
370              (Utilities::pow(GeometryInfo<dim>::max_children_per_cell,
371                              n_global_levels) -
372               1);
373     }
374 
375     template <typename T>
376     unsigned int
translate(const T & cell)377     translate(const T &cell) const
378     {
379       unsigned int id = 0;
380 
381       id += convert_cell_id_binary_type_to_level_coarse_cell_id<dim>(
382         cell->id().template to_binary<dim>());
383 
384       id += tree_sizes[cell->level()];
385 
386       return id;
387     }
388 
389     template <typename T>
390     unsigned int
translate(const T & cell,const unsigned int i)391     translate(const T &cell, const unsigned int i) const
392     {
393       return (translate(cell) - tree_sizes[cell->level()]) *
394                GeometryInfo<dim>::max_children_per_cell +
395              i + tree_sizes[cell->level() + 1];
396     }
397 
398     CellId
to_cell_id(const unsigned int id)399     to_cell_id(const unsigned int id) const
400     {
401       std::vector<std::uint8_t> child_indices;
402 
403       unsigned int id_temp = id;
404 
405       unsigned int level = 0;
406 
407       for (; level < n_global_levels; ++level)
408         if (id < tree_sizes[level])
409           break;
410       level -= 1;
411 
412       id_temp -= tree_sizes[level];
413 
414       for (unsigned int l = 0; l < level; ++l)
415         {
416           child_indices.push_back(id_temp %
417                                   GeometryInfo<dim>::max_children_per_cell);
418           id_temp /= GeometryInfo<dim>::max_children_per_cell;
419         }
420 
421       std::reverse(child_indices.begin(), child_indices.end());
422 
423       return {id_temp, child_indices}; // TODO
424     }
425 
426   private:
427     const unsigned int        n_coarse_cells;
428     const unsigned int        n_global_levels;
429     std::vector<unsigned int> tree_sizes;
430   };
431 
432   template <typename MeshType>
433   class FineDoFHandlerView
434   {
435   public:
FineDoFHandlerView(const MeshType & mesh_fine,const MeshType & mesh_coarse)436     FineDoFHandlerView(const MeshType &mesh_fine, const MeshType &mesh_coarse)
437       : mesh_fine(mesh_fine)
438       , mesh_coarse(mesh_coarse)
439       , communicator(get_mpi_comm(mesh_fine) /*TODO: fix for different comms*/)
440       , cell_id_translator(n_coarse_cells(mesh_fine),
441                            n_global_levels(mesh_fine))
442     {
443       AssertDimension(n_coarse_cells(mesh_fine), n_coarse_cells(mesh_coarse));
444       AssertIndexRange(n_global_levels(mesh_coarse),
445                        n_global_levels(mesh_fine) + 1);
446     }
447 
448     void
449     reinit(const IndexSet &is_dst_locally_owned,
450            const IndexSet &is_dst_remote_input,
451            const IndexSet &is_src_locally_owned,
452            const bool      check_if_elements_in_is_dst_remote_exist = false)
453     {
454 #ifndef DEAL_II_WITH_MPI
455       Assert(false, ExcNeedsMPI());
456       (void)is_dst_locally_owned;
457       (void)is_dst_remote_input;
458       (void)is_src_locally_owned;
459       (void)check_if_elements_in_is_dst_remote_exist;
460 #else
461       IndexSet is_dst_remote = is_dst_remote_input;
462 
463       if (check_if_elements_in_is_dst_remote_exist)
464         {
465           IndexSet is_dst_remote_potentially_relevant = is_dst_remote;
466           is_dst_remote.clear();
467 
468           is_dst_remote_potentially_relevant.subtract_set(is_dst_locally_owned);
469 
470           std::vector<unsigned int> owning_ranks_of_ghosts(
471             is_dst_remote_potentially_relevant.n_elements());
472 
473           {
474             Utilities::MPI::internal::ComputeIndexOwner::
475               ConsensusAlgorithmsPayload process(
476                 is_dst_locally_owned,
477                 is_dst_remote_potentially_relevant,
478                 communicator,
479                 owning_ranks_of_ghosts,
480                 false);
481 
482             Utilities::MPI::ConsensusAlgorithms::Selector<
483               std::pair<types::global_dof_index, types::global_dof_index>,
484               unsigned int>
485               consensus_algorithm(process, communicator);
486             consensus_algorithm.run();
487           }
488 
489           for (unsigned i = 0;
490                i < is_dst_remote_potentially_relevant.n_elements();
491                ++i)
492             if (owning_ranks_of_ghosts[i] != numbers::invalid_unsigned_int)
493               is_dst_remote.add_index(
494                 is_dst_remote_potentially_relevant.nth_index_in_set(i));
495         }
496 
497       // determine owner of remote cells
498       std::vector<unsigned int> is_dst_remote_owners(
499         is_dst_remote.n_elements());
500 
501       Utilities::MPI::internal::ComputeIndexOwner::ConsensusAlgorithmsPayload
502         process(is_dst_locally_owned,
503                 is_dst_remote,
504                 communicator,
505                 is_dst_remote_owners,
506                 true);
507 
508       Utilities::MPI::ConsensusAlgorithms::Selector<
509         std::pair<types::global_dof_index, types::global_dof_index>,
510         unsigned int>
511         consensus_algorithm(process, communicator);
512       consensus_algorithm.run();
513 
514       this->is_dst_locally_owned = is_dst_locally_owned;
515       this->is_dst_remote        = is_dst_remote;
516       this->is_src_locally_owned = is_src_locally_owned;
517 
518 #  if false
519         std::cout << "IS_SRC_LOCALLY_OWNED" << std::endl;
520         for (auto i : is_src_locally_owned)
521           std::cout << cell_id_translator.to_cell_id(i) << std::endl;
522         std::cout << std::endl << std::endl << std::endl;
523 
524 
525         std::cout << "IS_DST_LOCALLY_OWNED" << std::endl;
526         for (auto i : is_dst_locally_owned)
527           std::cout << cell_id_translator.to_cell_id(i) << std::endl;
528         std::cout << std::endl << std::endl << std::endl;
529 #  endif
530 
531       const auto &dof_handler_dst = mesh_fine; // TODO: remove
532       const auto &tria_dst        = mesh_fine.get_triangulation(); // TODO
533 
534       const unsigned int dofs_per_cell =
535         mesh_coarse.get_fe_collection()[0].dofs_per_cell;
536 
537       const auto targets_with_indexset = process.get_requesters();
538 
539       std::map<unsigned int, std::vector<unsigned int>> indices_to_be_sent;
540       std::vector<MPI_Request>                          requests;
541       requests.reserve(targets_with_indexset.size());
542 
543       {
544         std::vector<types::global_dof_index> indices(dofs_per_cell);
545 
546         for (const auto &i : targets_with_indexset)
547           {
548             indices_to_be_sent[i.first] = {};
549             auto &buffer                = indices_to_be_sent[i.first];
550 
551             for (auto cell_id : i.second)
552               {
553                 typename MeshType::cell_iterator cell(
554                   *cell_id_translator.to_cell_id(cell_id).to_cell(tria_dst),
555                   &dof_handler_dst);
556 
557                 cell->get_dof_indices(indices);
558                 buffer.insert(buffer.end(), indices.begin(), indices.end());
559               }
560 
561             requests.resize(requests.size() + 1);
562 
563             MPI_Isend(buffer.data(),
564                       buffer.size(),
565                       MPI_UNSIGNED,
566                       i.first,
567                       11,
568                       communicator,
569                       &requests.back());
570           }
571       }
572 
573 
574       std::vector<unsigned int> ghost_indices;
575 
576       // process local cells
577       {
578         std::vector<types::global_dof_index> indices(dofs_per_cell);
579 
580         for (const auto id : is_dst_locally_owned)
581           {
582             const auto cell_id = cell_id_translator.to_cell_id(id);
583 
584             typename MeshType::cell_iterator cell_(*cell_id.to_cell(tria_dst),
585                                                    &dof_handler_dst);
586 
587             cell_->get_dof_indices(indices);
588 
589             ghost_indices.insert(ghost_indices.end(),
590                                  indices.begin(),
591                                  indices.end());
592           }
593       }
594 
595       {
596         std::map<unsigned int, std::vector<unsigned int>> rank_to_ids;
597 
598         std::set<unsigned int> ranks;
599 
600         for (auto i : is_dst_remote_owners)
601           ranks.insert(i);
602 
603         for (auto i : ranks)
604           rank_to_ids[i] = {};
605 
606         for (unsigned int i = 0; i < is_dst_remote_owners.size(); ++i)
607           rank_to_ids[is_dst_remote_owners[i]].push_back(
608             is_dst_remote.nth_index_in_set(i));
609 
610 
611         for (unsigned int i = 0; i < ranks.size(); ++i)
612           {
613             MPI_Status status;
614             MPI_Probe(MPI_ANY_SOURCE, 11, communicator, &status);
615 
616             int message_length;
617             MPI_Get_count(&status, MPI_UNSIGNED, &message_length);
618 
619             std::vector<unsigned int> buffer(message_length);
620 
621             MPI_Recv(buffer.data(),
622                      buffer.size(),
623                      MPI_UNSIGNED,
624                      status.MPI_SOURCE,
625                      11,
626                      communicator,
627                      MPI_STATUS_IGNORE);
628 
629             ghost_indices.insert(ghost_indices.end(),
630                                  buffer.begin(),
631                                  buffer.end());
632 
633             const unsigned int rank = status.MPI_SOURCE;
634 
635             const auto ids = rank_to_ids[rank];
636 
637             std::vector<types::global_dof_index> indices(dofs_per_cell);
638 
639             for (unsigned int i = 0, k = 0; i < ids.size(); ++i)
640               {
641                 for (unsigned int j = 0; j < dofs_per_cell; ++j, ++k)
642                   indices[j] = buffer[k];
643                 map[ids[i]] = indices;
644               }
645           }
646 
647         MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
648       }
649 
650       std::sort(ghost_indices.begin(), ghost_indices.end());
651       ghost_indices.erase(std::unique(ghost_indices.begin(),
652                                       ghost_indices.end()),
653                           ghost_indices.end());
654 
655       this->is_extended_locally_owned = dof_handler_dst.locally_owned_dofs();
656 
657       this->is_extendende_ghosts = IndexSet(dof_handler_dst.n_dofs());
658       this->is_extendende_ghosts.add_indices(ghost_indices.begin(),
659                                              ghost_indices.end());
660       this->is_extendende_ghosts.subtract_set(this->is_extended_locally_owned);
661 
662 #endif
663     }
664 
665     FineDoFHandlerViewCell
get_cell(const typename MeshType::cell_iterator & cell)666     get_cell(const typename MeshType::cell_iterator &cell) const
667     {
668       const auto id = this->cell_id_translator.translate(cell);
669 
670       const bool is_cell_locally_owned =
671         this->is_dst_locally_owned.is_element(id);
672       const bool is_cell_remotly_owned = this->is_dst_remote.is_element(id);
673 
674       const bool has_cell_any_children = [&]() {
675         for (unsigned int i = 0;
676              i < GeometryInfo<MeshType::dimension>::max_children_per_cell;
677              ++i)
678           {
679             const auto j = this->cell_id_translator.translate(cell, i);
680 
681             if (this->is_dst_locally_owned.is_element(j))
682               return true;
683 
684             if (this->is_dst_remote.is_element(j))
685               return true;
686           }
687 
688         return false;
689       }();
690 
691       return FineDoFHandlerViewCell(
692         [has_cell_any_children]() { return has_cell_any_children; },
693         [cell, is_cell_locally_owned, is_cell_remotly_owned, id, this](
694           auto &dof_indices) {
695           if (is_cell_locally_owned)
696             {
697               (typename MeshType::cell_iterator(
698                  *cell->id().to_cell(mesh_fine.get_triangulation()),
699                  &mesh_fine))
700                 ->get_dof_indices(dof_indices);
701             }
702           else if (is_cell_remotly_owned)
703             {
704               dof_indices = map.at(id);
705             }
706           else
707             {
708               AssertThrow(false, ExcNotImplemented()); // should not happen!
709             }
710         });
711     }
712 
713     FineDoFHandlerViewCell
get_cell(const typename MeshType::cell_iterator & cell,const unsigned int c)714     get_cell(const typename MeshType::cell_iterator &cell,
715              const unsigned int                      c) const
716     {
717       const auto id = this->cell_id_translator.translate(cell, c);
718 
719       const bool is_cell_locally_owned =
720         this->is_dst_locally_owned.is_element(id);
721       const bool is_cell_remotly_owned = this->is_dst_remote.is_element(id);
722 
723       return FineDoFHandlerViewCell(
724         [cell]() {
725           AssertThrow(false, ExcNotImplemented()); // currently we do not need
726                                                    // children of children
727 
728           return false;
729         },
730         [cell, is_cell_locally_owned, is_cell_remotly_owned, c, id, this](
731           auto &dof_indices) {
732           if (is_cell_locally_owned)
733             {
734               (typename MeshType::cell_iterator(
735                  *cell->id().to_cell(mesh_fine.get_triangulation()),
736                  &mesh_fine))
737                 ->child(c)
738                 ->get_dof_indices(dof_indices);
739             }
740           else if (is_cell_remotly_owned)
741             {
742               dof_indices = map.at(id);
743             }
744           else
745             {
746               AssertThrow(false, ExcNotImplemented()); // should not happen!
747             }
748         });
749     }
750 
751     const IndexSet &
locally_owned_dofs()752     locally_owned_dofs() const
753     {
754       return is_extended_locally_owned;
755     }
756 
757     const IndexSet &
locally_relevant_dofs()758     locally_relevant_dofs() const
759     {
760       return is_extendende_ghosts;
761     }
762 
763   private:
764     const MeshType &mesh_fine;
765     const MeshType &mesh_coarse;
766     const MPI_Comm  communicator;
767 
768   protected:
769     const CellIDTranslator<MeshType::dimension> cell_id_translator;
770 
771   private:
772     IndexSet is_dst_locally_owned;
773     IndexSet is_dst_remote;
774     IndexSet is_src_locally_owned;
775 
776 
777     IndexSet is_extended_locally_owned;
778     IndexSet is_extendende_ghosts;
779 
780     std::map<unsigned int, std::vector<types::global_dof_index>> map;
781 
782     static unsigned int
n_coarse_cells(const MeshType & mesh)783     n_coarse_cells(const MeshType &mesh)
784     {
785       types::coarse_cell_id n_coarse_cells = 0;
786 
787       for (auto cell : mesh.get_triangulation().active_cell_iterators())
788         if (!cell->is_artificial())
789           n_coarse_cells =
790             std::max(n_coarse_cells, cell->id().get_coarse_cell_id());
791 
792       return Utilities::MPI::max(n_coarse_cells, get_mpi_comm(mesh)) + 1;
793     }
794 
795     static unsigned int
n_global_levels(const MeshType & mesh)796     n_global_levels(const MeshType &mesh)
797     {
798       return mesh.get_triangulation().n_global_levels();
799     }
800   };
801 
802   template <typename MeshType>
803   class GlobalCoarseningFineDoFHandlerView : public FineDoFHandlerView<MeshType>
804   {
805   public:
GlobalCoarseningFineDoFHandlerView(const MeshType & dof_handler_dst,const MeshType & dof_handler_src)806     GlobalCoarseningFineDoFHandlerView(const MeshType &dof_handler_dst,
807                                        const MeshType &dof_handler_src)
808       : FineDoFHandlerView<MeshType>(dof_handler_dst, dof_handler_src)
809     {
810       // get reference to triangulations
811       const auto &tria_dst = dof_handler_dst.get_triangulation();
812       const auto &tria_src = dof_handler_src.get_triangulation();
813 
814       // create index sets
815       IndexSet is_dst_locally_owned(this->cell_id_translator.size());
816       IndexSet is_dst_remote(this->cell_id_translator.size());
817       IndexSet is_src_locally_owned(this->cell_id_translator.size());
818 
819       for (auto cell : tria_dst.active_cell_iterators())
820         if (!cell->is_artificial() && cell->is_locally_owned())
821           is_dst_locally_owned.add_index(
822             this->cell_id_translator.translate(cell));
823 
824 
825       for (auto cell : tria_src.active_cell_iterators())
826         if (!cell->is_artificial() && cell->is_locally_owned())
827           {
828             is_src_locally_owned.add_index(
829               this->cell_id_translator.translate(cell));
830             is_dst_remote.add_index(this->cell_id_translator.translate(cell));
831 
832             if (cell->level() + 1u == tria_dst.n_global_levels())
833               continue;
834 
835             for (unsigned int i = 0;
836                  i < GeometryInfo<MeshType::dimension>::max_children_per_cell;
837                  ++i)
838               is_dst_remote.add_index(
839                 this->cell_id_translator.translate(cell, i));
840           }
841 
842       this->reinit(is_dst_locally_owned,
843                    is_dst_remote,
844                    is_src_locally_owned,
845                    true);
846     }
847   };
848 
849   class MGTwoLevelTransferImplementation
850   {
851   public:
852     template <int dim, typename Number, typename MeshType>
853     static void
reinit_geometric_transfer(const MeshType & dof_handler_fine,const MeshType & dof_handler_coarse,const dealii::AffineConstraints<Number> & constraint_fine,const dealii::AffineConstraints<Number> & constraint_coarse,MGTwoLevelTransfer<dim,LinearAlgebra::distributed::Vector<Number>> & transfer)854     reinit_geometric_transfer(
855       const MeshType &                         dof_handler_fine,
856       const MeshType &                         dof_handler_coarse,
857       const dealii::AffineConstraints<Number> &constraint_fine,
858       const dealii::AffineConstraints<Number> &constraint_coarse,
859       MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>
860         &transfer)
861     {
862       const GlobalCoarseningFineDoFHandlerView<MeshType> view(
863         dof_handler_fine, dof_handler_coarse);
864 
865       // copy constrain matrix; TODO: why only for the coarse level?
866       transfer.constraint_coarse.copy_from(constraint_coarse);
867 
868       // make sure that no hp is used
869       AssertDimension(dof_handler_coarse.get_fe_collection().size(), 1);
870       AssertDimension(dof_handler_fine.get_fe_collection().size(), 1);
871 
872       // extract number of components
873       AssertDimension(dof_handler_fine.get_fe().n_components(),
874                       dof_handler_coarse.get_fe().n_components());
875 
876       transfer.n_components = dof_handler_fine.get_fe().n_components();
877 
878       // create partitioners and vectors for internal purposes
879       {
880         // ... for fine mesh
881         {
882           transfer.partitioner_fine.reset(
883             new Utilities::MPI::Partitioner(view.locally_owned_dofs(),
884                                             view.locally_relevant_dofs(),
885                                             get_mpi_comm(dof_handler_fine)));
886           transfer.vec_fine.reinit(transfer.partitioner_fine);
887         }
888 
889         // ... coarse mesh (needed since user vector might be const)
890         {
891           IndexSet locally_relevant_dofs;
892           DoFTools::extract_locally_relevant_dofs(dof_handler_coarse,
893                                                   locally_relevant_dofs);
894 
895           transfer.partitioner_coarse.reset(new Utilities::MPI::Partitioner(
896             dof_handler_coarse.locally_owned_dofs(),
897             locally_relevant_dofs,
898             get_mpi_comm(dof_handler_coarse)));
899           transfer.vec_coarse.reinit(transfer.partitioner_coarse);
900         }
901       }
902 
903       // helper function: to process the fine level cells; function @p fu_non_refined is
904       // performed on cells that are not refined and @fu_refined is performed on
905       // children of cells that are refined
906       const auto process_cells =
907         [&view, &dof_handler_coarse](const auto &fu_non_refined,
908                                      const auto &fu_refined) {
909           // loop over all active locally-owned cells
910           for (const auto &cell_coarse :
911                dof_handler_coarse.active_cell_iterators())
912             {
913               if (cell_coarse->is_artificial() == true ||
914                   cell_coarse->is_locally_owned() == false)
915                 continue;
916 
917               // get a reference to the equivalent cell on the fine
918               // triangulation
919               const auto cell_coarse_on_fine_mesh = view.get_cell(cell_coarse);
920 
921               // check if cell has children
922               if (cell_coarse_on_fine_mesh.has_children())
923                 // ... cell has children -> process children
924                 for (unsigned int c = 0;
925                      c < GeometryInfo<dim>::max_children_per_cell;
926                      c++)
927                   fu_refined(cell_coarse, view.get_cell(cell_coarse, c), c);
928               else // ... cell has no children -> process cell
929                 fu_non_refined(cell_coarse, cell_coarse_on_fine_mesh);
930             }
931         };
932 
933       // set up two mg-schesmes
934       //   (0) no refinement -> identity
935       //   (1) h-refinement
936       transfer.schemes.resize(2);
937 
938       // check if FE is the same; TODO: better way?
939       AssertDimension(dof_handler_coarse.get_fe(0).dofs_per_cell,
940                       dof_handler_fine.get_fe(0).dofs_per_cell);
941 
942       // number of dofs on coarse and fine cells
943       transfer.schemes[0].dofs_per_cell_coarse =
944         transfer.schemes[0].dofs_per_cell_fine =
945           transfer.schemes[1].dofs_per_cell_coarse =
946             dof_handler_coarse.get_fe(0).dofs_per_cell;
947       transfer.schemes[1].dofs_per_cell_fine =
948         dof_handler_coarse.get_fe(0).dofs_per_cell *
949         GeometryInfo<dim>::max_children_per_cell;
950 
951       // degree of fe on coarse and fine cell
952       transfer.schemes[0].degree_coarse   = transfer.schemes[0].degree_fine =
953         transfer.schemes[1].degree_coarse = dof_handler_coarse.get_fe(0).degree;
954       transfer.schemes[1].degree_fine =
955         dof_handler_coarse.get_fe(0).degree * 2 + 1;
956 
957       // continuous or discontinuous
958       transfer.schemes[0].fine_element_is_continuous =
959         transfer.schemes[1].fine_element_is_continuous =
960           dof_handler_fine.get_fe(0).dofs_per_vertex > 0;
961 
962       // count coarse cells for each scheme (0, 1)
963       {
964         transfer.schemes[0].n_coarse_cells = 0; // reset
965         transfer.schemes[1].n_coarse_cells = 0;
966 
967         // count by looping over all coarse cells
968         process_cells(
969           [&](const auto &, const auto &) {
970             transfer.schemes[0].n_coarse_cells++;
971           },
972           [&](const auto &, const auto &, const auto c) {
973             if (c == 0)
974               transfer.schemes[1].n_coarse_cells++;
975           });
976       }
977 
978 
979       const auto cell_local_chilren_indices =
980         get_child_offsets<dim>(transfer.schemes[0].dofs_per_cell_coarse,
981                                dof_handler_fine.get_fe(0).degree + 1,
982                                dof_handler_fine.get_fe(0).degree);
983 
984 
985       // indices
986       {
987         transfer.schemes[0].level_dof_indices_fine.resize(
988           transfer.schemes[0].dofs_per_cell_fine *
989           transfer.schemes[0].n_coarse_cells);
990         transfer.schemes[0].level_dof_indices_coarse.resize(
991           transfer.schemes[0].dofs_per_cell_coarse *
992           transfer.schemes[0].n_coarse_cells);
993 
994         transfer.schemes[1].level_dof_indices_fine.resize(
995           transfer.schemes[1].dofs_per_cell_fine *
996           transfer.schemes[1].n_coarse_cells);
997         transfer.schemes[1].level_dof_indices_coarse.resize(
998           transfer.schemes[1].dofs_per_cell_coarse *
999           transfer.schemes[1].n_coarse_cells);
1000 
1001         std::vector<types::global_dof_index> local_dof_indices(
1002           transfer.schemes[0].dofs_per_cell_coarse);
1003 
1004         // ---------------------- lexicographic_numbering ----------------------
1005         std::vector<unsigned int> lexicographic_numbering;
1006         {
1007           const Quadrature<1> dummy_quadrature(
1008             std::vector<Point<1>>(1, Point<1>()));
1009           internal::MatrixFreeFunctions::ShapeInfo<Number> shape_info;
1010           shape_info.reinit(dummy_quadrature, dof_handler_fine.get_fe(0), 0);
1011           lexicographic_numbering = shape_info.lexicographic_numbering;
1012         }
1013 
1014         // ------------------------------ indices ------------------------------
1015         unsigned int *level_dof_indices_coarse_0 =
1016           &transfer.schemes[0].level_dof_indices_coarse[0];
1017         unsigned int *level_dof_indices_fine_0 =
1018           &transfer.schemes[0].level_dof_indices_fine[0];
1019 
1020         unsigned int *level_dof_indices_coarse_1 =
1021           &transfer.schemes[1].level_dof_indices_coarse[0];
1022         unsigned int *level_dof_indices_fine_1 =
1023           &transfer.schemes[1].level_dof_indices_fine[0];
1024 
1025         process_cells(
1026           [&](const auto &cell_coarse, const auto &cell_fine) {
1027             // parent
1028             {
1029               cell_coarse->get_dof_indices(local_dof_indices);
1030               for (unsigned int i = 0;
1031                    i < transfer.schemes[0].dofs_per_cell_coarse;
1032                    i++)
1033                 level_dof_indices_coarse_0[i] =
1034                   transfer.partitioner_coarse->global_to_local(
1035                     local_dof_indices[lexicographic_numbering[i]]);
1036             }
1037 
1038             // child
1039             {
1040               cell_fine.get_dof_indices(local_dof_indices);
1041               for (unsigned int i = 0;
1042                    i < transfer.schemes[0].dofs_per_cell_coarse;
1043                    i++)
1044                 level_dof_indices_fine_0[i] =
1045                   transfer.partitioner_fine->global_to_local(
1046                     local_dof_indices[lexicographic_numbering[i]]);
1047             }
1048 
1049             // move pointers
1050             {
1051               level_dof_indices_coarse_0 +=
1052                 transfer.schemes[0].dofs_per_cell_coarse;
1053               level_dof_indices_fine_0 +=
1054                 transfer.schemes[0].dofs_per_cell_fine;
1055             }
1056           },
1057           [&](const auto &cell_coarse, const auto &cell_fine, const auto c) {
1058             // parent (only once at the beginning)
1059             if (c == 0)
1060               {
1061                 cell_coarse->get_dof_indices(local_dof_indices);
1062                 for (unsigned int i = 0;
1063                      i < transfer.schemes[1].dofs_per_cell_coarse;
1064                      i++)
1065                   level_dof_indices_coarse_1[i] =
1066                     transfer.partitioner_coarse->global_to_local(
1067                       local_dof_indices[lexicographic_numbering[i]]);
1068               }
1069 
1070             // child
1071             {
1072               cell_fine.get_dof_indices(local_dof_indices);
1073               for (unsigned int i = 0;
1074                    i < transfer.schemes[1].dofs_per_cell_coarse;
1075                    i++)
1076                 level_dof_indices_fine_1[cell_local_chilren_indices[c][i]] =
1077                   transfer.partitioner_fine->global_to_local(
1078                     local_dof_indices[lexicographic_numbering[i]]);
1079             }
1080 
1081             // move pointers (only once at the end)
1082             if (c + 1 == GeometryInfo<dim>::max_children_per_cell)
1083               {
1084                 level_dof_indices_coarse_1 +=
1085                   transfer.schemes[1].dofs_per_cell_coarse;
1086                 level_dof_indices_fine_1 +=
1087                   transfer.schemes[1].dofs_per_cell_fine;
1088               }
1089           });
1090       }
1091 
1092       // ------------- prolongation matrix (0) -> identity matrix --------------
1093       {
1094         AssertDimension(dof_handler_fine.get_fe(0).n_base_elements(), 1);
1095         std::string fe_name =
1096           dof_handler_fine.get_fe(0).base_element(0).get_name();
1097         {
1098           const std::size_t template_starts = fe_name.find_first_of('<');
1099           Assert(fe_name[template_starts + 1] ==
1100                    (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1101                  ExcInternalError());
1102           fe_name[template_starts + 1] = '1';
1103         }
1104         const std::unique_ptr<FiniteElement<1>> fe(
1105           FETools::get_fe_by_name<1, 1>(fe_name));
1106 
1107         transfer.schemes[0].prolongation_matrix_1d.resize(fe->dofs_per_cell *
1108                                                           fe->dofs_per_cell);
1109 
1110         for (unsigned int i = 0; i < fe->dofs_per_cell; i++)
1111           transfer.schemes[0]
1112             .prolongation_matrix_1d[i + i * fe->dofs_per_cell] = Number(1.0);
1113       }
1114 
1115       // ----------------------- prolongation matrix (1) -----------------------
1116       {
1117         AssertDimension(dof_handler_fine.get_fe(0).n_base_elements(), 1);
1118         std::string fe_name =
1119           dof_handler_fine.get_fe(0).base_element(0).get_name();
1120         {
1121           const std::size_t template_starts = fe_name.find_first_of('<');
1122           Assert(fe_name[template_starts + 1] ==
1123                    (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1124                  ExcInternalError());
1125           fe_name[template_starts + 1] = '1';
1126         }
1127         const std::unique_ptr<FiniteElement<1>> fe(
1128           FETools::get_fe_by_name<1, 1>(fe_name));
1129 
1130         std::vector<unsigned int> renumbering(fe->dofs_per_cell);
1131         {
1132           AssertIndexRange(fe->dofs_per_vertex, 2);
1133           renumbering[0] = 0;
1134           for (unsigned int i = 0; i < fe->dofs_per_line; ++i)
1135             renumbering[i + fe->dofs_per_vertex] =
1136               GeometryInfo<1>::vertices_per_cell * fe->dofs_per_vertex + i;
1137           if (fe->dofs_per_vertex > 0)
1138             renumbering[fe->dofs_per_cell - fe->dofs_per_vertex] =
1139               fe->dofs_per_vertex;
1140         }
1141 
1142         // TODO: data structures are saved in form of DG data structures here
1143         const unsigned int shift           = fe->dofs_per_cell;
1144         const unsigned int n_child_dofs_1d = fe->dofs_per_cell * 2;
1145 
1146         transfer.schemes[1].prolongation_matrix_1d.resize(fe->dofs_per_cell *
1147                                                           n_child_dofs_1d);
1148 
1149         for (unsigned int c = 0; c < GeometryInfo<1>::max_children_per_cell;
1150              ++c)
1151           for (unsigned int i = 0; i < fe->dofs_per_cell; ++i)
1152             for (unsigned int j = 0; j < fe->dofs_per_cell; ++j)
1153               transfer.schemes[1]
1154                 .prolongation_matrix_1d[i * n_child_dofs_1d + j + c * shift] =
1155                 fe->get_prolongation_matrix(c)(renumbering[j], renumbering[i]);
1156       }
1157 
1158 
1159       // ------------------------------- weights -------------------------------
1160       if (transfer.schemes[0].fine_element_is_continuous)
1161         {
1162           LinearAlgebra::distributed::Vector<Number> touch_count, touch_count_;
1163 
1164           touch_count.reinit(transfer.partitioner_fine);
1165 
1166           IndexSet locally_relevant_dofs;
1167           DoFTools::extract_locally_relevant_dofs(dof_handler_fine,
1168                                                   locally_relevant_dofs);
1169 
1170           const auto partitioner_fine_ =
1171             std::make_shared<Utilities::MPI::Partitioner>(
1172               dof_handler_fine.locally_owned_dofs(),
1173               locally_relevant_dofs,
1174               get_mpi_comm(dof_handler_fine));
1175           transfer.vec_fine.reinit(transfer.partitioner_fine);
1176 
1177           touch_count_.reinit(partitioner_fine_);
1178 
1179           std::vector<types::global_dof_index> local_dof_indices(
1180             transfer.schemes[0].dofs_per_cell_coarse);
1181 
1182           for (auto cell : dof_handler_fine.active_cell_iterators())
1183             {
1184               if (cell->is_locally_owned() == false)
1185                 continue;
1186 
1187               cell->get_dof_indices(local_dof_indices);
1188 
1189               for (auto i : local_dof_indices)
1190                 if (constraint_fine.is_constrained(i) == false)
1191                   touch_count_[i] += 1;
1192             }
1193 
1194           touch_count_.compress(VectorOperation::add);
1195 
1196           for (unsigned int i = 0; i < touch_count_.local_size(); ++i)
1197             touch_count_.local_element(i) =
1198               constraint_fine.is_constrained(
1199                 touch_count_.get_partitioner()->local_to_global(i)) ?
1200                 Number(0.) :
1201                 Number(1.) / touch_count_.local_element(i);
1202 
1203           // TODO: needed?
1204           touch_count_.update_ghost_values();
1205 
1206 
1207           // copy weights to other indexset
1208           touch_count.copy_locally_owned_data_from(touch_count_);
1209           touch_count.update_ghost_values();
1210 
1211           transfer.schemes[0].weights.resize(
1212             transfer.schemes[0].n_coarse_cells *
1213             transfer.schemes[0].dofs_per_cell_fine);
1214           transfer.schemes[1].weights.resize(
1215             transfer.schemes[1].n_coarse_cells *
1216             transfer.schemes[1].dofs_per_cell_fine);
1217 
1218           Number *      weights_0 = &transfer.schemes[0].weights[0];
1219           Number *      weights_1 = &transfer.schemes[1].weights[0];
1220           unsigned int *dof_indices_fine_0 =
1221             &transfer.schemes[0].level_dof_indices_fine[0];
1222           unsigned int *dof_indices_fine_1 =
1223             &transfer.schemes[1].level_dof_indices_fine[0];
1224 
1225           process_cells(
1226             [&](const auto &, const auto &) {
1227               for (unsigned int i = 0;
1228                    i < transfer.schemes[0].dofs_per_cell_fine;
1229                    i++)
1230                 weights_0[i] = touch_count.local_element(dof_indices_fine_0[i]);
1231 
1232               dof_indices_fine_0 += transfer.schemes[0].dofs_per_cell_fine;
1233               weights_0 += transfer.schemes[0].dofs_per_cell_fine;
1234             },
1235             [&](const auto &, const auto &, const auto c) {
1236               for (unsigned int i = 0;
1237                    i < transfer.schemes[1].dofs_per_cell_coarse;
1238                    i++)
1239                 weights_1[cell_local_chilren_indices[c][i]] =
1240                   touch_count.local_element(
1241                     dof_indices_fine_1[cell_local_chilren_indices[c][i]]);
1242 
1243               // move pointers (only once at the end)
1244               if (c + 1 == GeometryInfo<dim>::max_children_per_cell)
1245                 {
1246                   dof_indices_fine_1 += transfer.schemes[1].dofs_per_cell_fine;
1247                   weights_1 += transfer.schemes[1].dofs_per_cell_fine;
1248                 }
1249             });
1250         }
1251     }
1252 
1253 
1254 
1255     template <int dim, typename Number, typename MeshType>
1256     static void
reinit_polynomial_transfer(const MeshType & dof_handler_fine,const MeshType & dof_handler_coarse,const dealii::AffineConstraints<Number> & constraint_fine,const dealii::AffineConstraints<Number> & constraint_coarse,MGTwoLevelTransfer<dim,LinearAlgebra::distributed::Vector<Number>> & transfer)1257     reinit_polynomial_transfer(
1258       const MeshType &                         dof_handler_fine,
1259       const MeshType &                         dof_handler_coarse,
1260       const dealii::AffineConstraints<Number> &constraint_fine,
1261       const dealii::AffineConstraints<Number> &constraint_coarse,
1262       MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>
1263         &transfer)
1264     {
1265       AssertDimension(dof_handler_fine.get_triangulation().n_active_cells(),
1266                       dof_handler_coarse.get_triangulation().n_active_cells());
1267 
1268       // extract number of components
1269       AssertDimension(dof_handler_fine.get_fe_collection().n_components(),
1270                       dof_handler_coarse.get_fe_collection().n_components());
1271 
1272       transfer.n_components =
1273         dof_handler_fine.get_fe_collection().n_components();
1274 
1275       const auto process_cells = [&](const auto &fu) {
1276         typename MeshType::active_cell_iterator            //
1277           cell_coarse = dof_handler_coarse.begin_active(), //
1278           end_coarse  = dof_handler_coarse.end(),          //
1279           cell_fine   = dof_handler_fine.begin_active();
1280 
1281         for (; cell_coarse != end_coarse; cell_coarse++, cell_fine++)
1282           {
1283             if (!cell_coarse->is_locally_owned())
1284               continue;
1285 
1286             fu(cell_coarse, cell_fine);
1287           }
1288       };
1289 
1290       std::map<std::pair<unsigned int, unsigned int>, unsigned int>
1291         fe_index_pairs;
1292 
1293       process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1294         fe_index_pairs.emplace(
1295           std::pair<unsigned int, unsigned int>(cell_coarse->active_fe_index(),
1296                                                 cell_fine->active_fe_index()),
1297           0);
1298       });
1299 
1300       unsigned int counter = 0;
1301       for (auto &f : fe_index_pairs)
1302         f.second = counter++;
1303 
1304       transfer.schemes.resize(fe_index_pairs.size());
1305 
1306       // extract number of coarse cells
1307       {
1308         for (auto &scheme : transfer.schemes)
1309           scheme.n_coarse_cells = 0;
1310         process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1311           transfer
1312             .schemes[fe_index_pairs[std::pair<unsigned int, unsigned int>(
1313               cell_coarse->active_fe_index(), cell_fine->active_fe_index())]]
1314             .n_coarse_cells++;
1315         });
1316       }
1317 
1318       for (const auto &fe_index_pair : fe_index_pairs)
1319         {
1320           transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse =
1321             dof_handler_coarse.get_fe(fe_index_pair.first.first).dofs_per_cell;
1322           transfer.schemes[fe_index_pair.second].dofs_per_cell_fine =
1323             dof_handler_fine.get_fe(fe_index_pair.first.second).dofs_per_cell;
1324 
1325           transfer.schemes[fe_index_pair.second].degree_coarse =
1326             dof_handler_coarse.get_fe(fe_index_pair.first.first).degree;
1327           transfer.schemes[fe_index_pair.second].degree_fine =
1328             dof_handler_fine.get_fe(fe_index_pair.first.second).degree;
1329 
1330           transfer.schemes[fe_index_pair.second].fine_element_is_continuous =
1331             dof_handler_fine.get_fe(fe_index_pair.first.second)
1332               .dofs_per_vertex > 0;
1333         }
1334 
1335       transfer.constraint_coarse.copy_from(constraint_coarse);
1336 
1337       const auto comm = get_mpi_comm(dof_handler_coarse);
1338       {
1339         IndexSet locally_relevant_dofs;
1340         DoFTools::extract_locally_relevant_dofs(dof_handler_fine,
1341                                                 locally_relevant_dofs);
1342 
1343         transfer.partitioner_fine.reset(new Utilities::MPI::Partitioner(
1344           dof_handler_fine.locally_owned_dofs(), locally_relevant_dofs, comm));
1345         transfer.vec_fine.reinit(transfer.partitioner_fine);
1346       }
1347       {
1348         IndexSet locally_relevant_dofs;
1349         DoFTools::extract_locally_relevant_dofs(dof_handler_coarse,
1350                                                 locally_relevant_dofs);
1351 
1352         transfer.partitioner_coarse.reset(new Utilities::MPI::Partitioner(
1353           dof_handler_coarse.locally_owned_dofs(),
1354           locally_relevant_dofs,
1355           comm));
1356         transfer.vec_coarse.reinit(transfer.partitioner_coarse);
1357       }
1358 
1359       {
1360         std::vector<std::vector<unsigned int>> lexicographic_numbering_fine(
1361           fe_index_pairs.size());
1362         std::vector<std::vector<unsigned int>> lexicographic_numbering_coarse(
1363           fe_index_pairs.size());
1364         std::vector<std::vector<types::global_dof_index>>
1365           local_dof_indices_coarse(fe_index_pairs.size());
1366         std::vector<std::vector<types::global_dof_index>>
1367           local_dof_indices_fine(fe_index_pairs.size());
1368 
1369         for (const auto &fe_index_pair : fe_index_pairs)
1370           {
1371             local_dof_indices_coarse[fe_index_pair.second].resize(
1372               transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse);
1373             local_dof_indices_fine[fe_index_pair.second].resize(
1374               transfer.schemes[fe_index_pair.second].dofs_per_cell_fine);
1375 
1376             transfer.schemes[fe_index_pair.second]
1377               .level_dof_indices_fine.resize(
1378                 transfer.schemes[fe_index_pair.second].dofs_per_cell_fine *
1379                 transfer.schemes[fe_index_pair.second].n_coarse_cells);
1380             transfer.schemes[fe_index_pair.second]
1381               .level_dof_indices_coarse.resize(
1382                 transfer.schemes[fe_index_pair.second].dofs_per_cell_coarse *
1383                 transfer.schemes[fe_index_pair.second].n_coarse_cells);
1384 
1385 
1386             // ------------------- lexicographic_numbering  --------------------
1387             {
1388               const Quadrature<1> dummy_quadrature(
1389                 std::vector<Point<1>>(1, Point<1>()));
1390               internal::MatrixFreeFunctions::ShapeInfo<Number> shape_info;
1391               shape_info.reinit(dummy_quadrature,
1392                                 dof_handler_fine.get_fe(
1393                                   fe_index_pair.first.second),
1394                                 0);
1395               lexicographic_numbering_fine[fe_index_pair.second] =
1396                 shape_info.lexicographic_numbering;
1397 
1398               shape_info.reinit(dummy_quadrature,
1399                                 dof_handler_coarse.get_fe(
1400                                   fe_index_pair.first.first),
1401                                 0);
1402               lexicographic_numbering_coarse[fe_index_pair.second] =
1403                 shape_info.lexicographic_numbering;
1404             }
1405           }
1406 
1407         // ------------------------------ indices  -----------------------------
1408         std::vector<unsigned int *> level_dof_indices_coarse_(
1409           fe_index_pairs.size());
1410         std::vector<unsigned int *> level_dof_indices_fine_(
1411           fe_index_pairs.size());
1412 
1413         for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1414           {
1415             level_dof_indices_coarse_[i] =
1416               &transfer.schemes[i].level_dof_indices_coarse[0];
1417             level_dof_indices_fine_[i] =
1418               &transfer.schemes[i].level_dof_indices_fine[0];
1419           }
1420 
1421         process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1422           const auto fe_pair_no =
1423             fe_index_pairs[std::pair<unsigned int, unsigned int>(
1424               cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1425 
1426           cell_coarse->get_dof_indices(local_dof_indices_coarse[fe_pair_no]);
1427           for (unsigned int i = 0;
1428                i < transfer.schemes[fe_pair_no].dofs_per_cell_coarse;
1429                i++)
1430             level_dof_indices_coarse_[fe_pair_no][i] =
1431               transfer.partitioner_coarse->global_to_local(
1432                 local_dof_indices_coarse
1433                   [fe_pair_no][lexicographic_numbering_coarse[fe_pair_no][i]]);
1434 
1435 
1436           cell_fine->get_dof_indices(local_dof_indices_fine[fe_pair_no]);
1437           for (unsigned int i = 0;
1438                i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1439                i++)
1440             level_dof_indices_fine_[fe_pair_no][i] =
1441               transfer.partitioner_fine->global_to_local(
1442                 local_dof_indices_fine
1443                   [fe_pair_no][lexicographic_numbering_fine[fe_pair_no][i]]);
1444 
1445 
1446           level_dof_indices_coarse_[fe_pair_no] +=
1447             transfer.schemes[fe_pair_no].dofs_per_cell_coarse;
1448           level_dof_indices_fine_[fe_pair_no] +=
1449             transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1450         });
1451       }
1452 
1453       // ------------------------- prolongation matrix -------------------------
1454       for (auto const &fe_index_pair_ : fe_index_pairs)
1455         {
1456           const auto &fe_index_pair = fe_index_pair_.first;
1457           const auto &fe_index_no   = fe_index_pair_.second;
1458 
1459           AssertDimension(
1460             dof_handler_fine.get_fe(fe_index_pair.second).n_base_elements(), 1);
1461           std::string fe_name_fine =
1462             dof_handler_fine.get_fe(fe_index_pair.second)
1463               .base_element(0)
1464               .get_name();
1465           {
1466             const std::size_t template_starts = fe_name_fine.find_first_of('<');
1467             Assert(fe_name_fine[template_starts + 1] ==
1468                      (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1469                    ExcInternalError());
1470             fe_name_fine[template_starts + 1] = '1';
1471           }
1472           const std::unique_ptr<FiniteElement<1>> fe_fine(
1473             FETools::get_fe_by_name<1, 1>(fe_name_fine));
1474 
1475           std::vector<unsigned int> renumbering_fine(fe_fine->dofs_per_cell);
1476           {
1477             AssertIndexRange(fe_fine->dofs_per_vertex, 2);
1478             renumbering_fine[0] = 0;
1479             for (unsigned int i = 0; i < fe_fine->dofs_per_line; ++i)
1480               renumbering_fine[i + fe_fine->dofs_per_vertex] =
1481                 GeometryInfo<1>::vertices_per_cell * fe_fine->dofs_per_vertex +
1482                 i;
1483             if (fe_fine->dofs_per_vertex > 0)
1484               renumbering_fine[fe_fine->dofs_per_cell -
1485                                fe_fine->dofs_per_vertex] =
1486                 fe_fine->dofs_per_vertex;
1487           }
1488 
1489 
1490 
1491           AssertDimension(
1492             dof_handler_coarse.get_fe(fe_index_pair.first).n_base_elements(),
1493             1);
1494           std::string fe_name_coarse =
1495             dof_handler_coarse.get_fe(fe_index_pair.first)
1496               .base_element(0)
1497               .get_name();
1498           {
1499             const std::size_t template_starts =
1500               fe_name_coarse.find_first_of('<');
1501             Assert(fe_name_coarse[template_starts + 1] ==
1502                      (dim == 1 ? '1' : (dim == 2 ? '2' : '3')),
1503                    ExcInternalError());
1504             fe_name_coarse[template_starts + 1] = '1';
1505           }
1506           const std::unique_ptr<FiniteElement<1>> fe_coarse(
1507             FETools::get_fe_by_name<1, 1>(fe_name_coarse));
1508 
1509           std::vector<unsigned int> renumbering_coarse(
1510             fe_coarse->dofs_per_cell);
1511           {
1512             AssertIndexRange(fe_coarse->dofs_per_vertex, 2);
1513             renumbering_coarse[0] = 0;
1514             for (unsigned int i = 0; i < fe_coarse->dofs_per_line; ++i)
1515               renumbering_coarse[i + fe_coarse->dofs_per_vertex] =
1516                 GeometryInfo<1>::vertices_per_cell *
1517                   fe_coarse->dofs_per_vertex +
1518                 i;
1519             if (fe_coarse->dofs_per_vertex > 0)
1520               renumbering_coarse[fe_coarse->dofs_per_cell -
1521                                  fe_coarse->dofs_per_vertex] =
1522                 fe_coarse->dofs_per_vertex;
1523           }
1524 
1525 
1526 
1527           FullMatrix<double> matrix(fe_fine->dofs_per_cell,
1528                                     fe_coarse->dofs_per_cell);
1529           FETools::get_projection_matrix(*fe_coarse, *fe_fine, matrix);
1530           transfer.schemes[fe_index_no].prolongation_matrix_1d.resize(
1531             fe_fine->dofs_per_cell * fe_coarse->dofs_per_cell);
1532 
1533           for (unsigned int i = 0, k = 0; i < fe_coarse->dofs_per_cell; ++i)
1534             for (unsigned int j = 0; j < fe_fine->dofs_per_cell; ++j, ++k)
1535               transfer.schemes[fe_index_no].prolongation_matrix_1d[k] =
1536                 matrix(renumbering_fine[j], renumbering_coarse[i]);
1537         }
1538 
1539       // ------------------------------- weights -------------------------------
1540       const bool fine_element_is_continuous = Utilities::MPI::max(
1541         static_cast<unsigned int>(
1542           transfer.schemes.size() > 0 ?
1543             transfer.schemes.front().fine_element_is_continuous :
1544             false),
1545         comm);
1546       if (fine_element_is_continuous)
1547         {
1548           for (auto &scheme : transfer.schemes)
1549             scheme.weights.resize(scheme.n_coarse_cells *
1550                                   scheme.dofs_per_cell_fine);
1551 
1552           LinearAlgebra::distributed::Vector<Number> touch_count;
1553           touch_count.reinit(transfer.partitioner_fine);
1554 
1555           std::vector<unsigned int *> level_dof_indices_fine_(
1556             fe_index_pairs.size());
1557           std::vector<Number *> weights_(fe_index_pairs.size());
1558 
1559           for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1560             level_dof_indices_fine_[i] =
1561               &transfer.schemes[i].level_dof_indices_fine[0];
1562 
1563           process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1564             const auto fe_pair_no =
1565               fe_index_pairs[std::pair<unsigned int, unsigned int>(
1566                 cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1567 
1568             for (unsigned int i = 0;
1569                  i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1570                  i++)
1571               if (constraint_fine.is_constrained(
1572                     transfer.partitioner_fine->local_to_global(
1573                       level_dof_indices_fine_[fe_pair_no][i])) == false)
1574                 touch_count.local_element(
1575                   level_dof_indices_fine_[fe_pair_no][i]) += 1;
1576 
1577             level_dof_indices_fine_[fe_pair_no] +=
1578               transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1579           });
1580 
1581           touch_count.compress(VectorOperation::add);
1582           touch_count.update_ghost_values();
1583 
1584           for (unsigned int i = 0; i < fe_index_pairs.size(); i++)
1585             {
1586               level_dof_indices_fine_[i] =
1587                 &transfer.schemes[i].level_dof_indices_fine[0];
1588               weights_[i] = &transfer.schemes[i].weights[0];
1589             }
1590 
1591           process_cells([&](const auto &cell_coarse, const auto &cell_fine) {
1592             const auto fe_pair_no =
1593               fe_index_pairs[std::pair<unsigned int, unsigned int>(
1594                 cell_coarse->active_fe_index(), cell_fine->active_fe_index())];
1595 
1596             for (unsigned int i = 0;
1597                  i < transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1598                  i++)
1599               if (constraint_fine.is_constrained(
1600                     transfer.partitioner_fine->local_to_global(
1601                       level_dof_indices_fine_[fe_pair_no][i])) == true)
1602                 weights_[fe_pair_no][i] = Number(0.);
1603               else
1604                 weights_[fe_pair_no][i] =
1605                   Number(1.) / touch_count.local_element(
1606                                  level_dof_indices_fine_[fe_pair_no][i]);
1607 
1608             level_dof_indices_fine_[fe_pair_no] +=
1609               transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1610             weights_[fe_pair_no] +=
1611               transfer.schemes[fe_pair_no].dofs_per_cell_fine;
1612           });
1613         }
1614     }
1615   };
1616 
1617 } // namespace internal
1618 
1619 
1620 template <int dim, typename Number>
1621 void
prolongate(LinearAlgebra::distributed::Vector<Number> & dst,const LinearAlgebra::distributed::Vector<Number> & src)1622 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::prolongate(
1623   LinearAlgebra::distributed::Vector<Number> &      dst,
1624   const LinearAlgebra::distributed::Vector<Number> &src) const
1625 {
1626   using VectorizedArrayType = VectorizedArray<Number>;
1627 
1628   const unsigned int n_lanes = VectorizedArrayType::size();
1629 
1630   this->vec_coarse.copy_locally_owned_data_from(src);
1631   this->vec_coarse.update_ghost_values();
1632   this->constraint_coarse.distribute(this->vec_coarse);
1633   this->vec_coarse
1634     .update_ghost_values(); // note: make sure that ghost values are set
1635 
1636   this->vec_fine = Number(0.);
1637 
1638   AlignedVector<VectorizedArrayType> evaluation_data_fine;
1639   AlignedVector<VectorizedArrayType> evaluation_data_coarse;
1640 
1641   for (const auto &scheme : schemes)
1642     {
1643       // identity -> take short cut and work directly on global vectors
1644       if (scheme.degree_fine == scheme.degree_coarse)
1645         {
1646           const unsigned int *indices_fine =
1647             scheme.level_dof_indices_fine.data();
1648           const unsigned int *indices_coarse =
1649             scheme.level_dof_indices_coarse.data();
1650           const Number *weights = nullptr;
1651 
1652           if (scheme.fine_element_is_continuous)
1653             weights = scheme.weights.data();
1654 
1655           for (unsigned int cell = 0; cell < scheme.n_coarse_cells; ++cell)
1656             {
1657               for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1658                 this->vec_fine.local_element(indices_fine[i]) +=
1659                   this->vec_coarse.local_element(indices_coarse[i]) *
1660                   (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1661 
1662               indices_fine += scheme.dofs_per_cell_fine;
1663               indices_coarse += scheme.dofs_per_cell_coarse;
1664 
1665               if (scheme.fine_element_is_continuous)
1666                 weights += scheme.dofs_per_cell_fine;
1667             }
1668 
1669           continue;
1670         }
1671 
1672       // general case -> local restriction is needed
1673       evaluation_data_fine.resize(scheme.dofs_per_cell_fine);
1674       evaluation_data_coarse.resize(scheme.dofs_per_cell_fine);
1675 
1676       CellTransferFactory cell_transfer(scheme.degree_fine,
1677                                         scheme.degree_coarse);
1678 
1679       const unsigned int n_scalar_dofs_fine =
1680         Utilities::pow(scheme.degree_fine + 1, dim);
1681       const unsigned int n_scalar_dofs_coarse =
1682         Utilities::pow(scheme.degree_coarse + 1, dim);
1683 
1684       for (unsigned int cell = 0; cell < scheme.n_coarse_cells; cell += n_lanes)
1685         {
1686           const unsigned int n_lanes_filled =
1687             (cell + n_lanes > scheme.n_coarse_cells) ?
1688               (scheme.n_coarse_cells - cell) :
1689               n_lanes;
1690 
1691           // read from source vector
1692           {
1693             const unsigned int *indices =
1694               &scheme
1695                  .level_dof_indices_coarse[cell * scheme.dofs_per_cell_coarse];
1696             for (unsigned int v = 0; v < n_lanes_filled; ++v)
1697               {
1698                 for (unsigned int i = 0; i < scheme.dofs_per_cell_coarse; ++i)
1699                   evaluation_data_coarse[i][v] =
1700                     this->vec_coarse.local_element(indices[i]);
1701                 indices += scheme.dofs_per_cell_coarse;
1702               }
1703           }
1704 
1705           // ---------------------------- coarse -----------------------------
1706           for (int c = n_components - 1; c >= 0; --c)
1707             {
1708               CellProlongator<dim, VectorizedArrayType> cell_prolongator(
1709                 scheme.prolongation_matrix_1d,
1710                 evaluation_data_coarse.begin() + c * n_scalar_dofs_coarse,
1711                 evaluation_data_fine.begin() + c * n_scalar_dofs_fine);
1712 
1713               cell_transfer.run(cell_prolongator);
1714             }
1715           // ------------------------------ fine -----------------------------
1716 
1717           // weight and write into dst vector
1718           {
1719             const unsigned int *indices =
1720               &scheme.level_dof_indices_fine[cell * scheme.dofs_per_cell_fine];
1721             const Number *weights = nullptr;
1722 
1723             if (scheme.fine_element_is_continuous)
1724               weights = &scheme.weights[cell * scheme.dofs_per_cell_fine];
1725 
1726             for (unsigned int v = 0; v < n_lanes_filled; ++v)
1727               {
1728                 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1729                   this->vec_fine.local_element(indices[i]) +=
1730                     evaluation_data_fine[i][v] *
1731                     (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1732 
1733                 indices += scheme.dofs_per_cell_fine;
1734 
1735                 if (scheme.fine_element_is_continuous)
1736                   weights += scheme.dofs_per_cell_fine;
1737               }
1738           }
1739         }
1740     }
1741 
1742   this->vec_coarse.zero_out_ghosts(); // clear ghost values; else compress in
1743                                       // do_restrict_add does not work
1744 
1745   if (schemes.size() > 0 && schemes.front().fine_element_is_continuous)
1746     this->vec_fine.compress(VectorOperation::add);
1747 
1748   dst.copy_locally_owned_data_from(this->vec_fine);
1749 }
1750 
1751 
1752 
1753 template <int dim, typename Number>
1754 void
1755 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
restrict_and_add(LinearAlgebra::distributed::Vector<Number> & dst,const LinearAlgebra::distributed::Vector<Number> & src)1756   restrict_and_add(LinearAlgebra::distributed::Vector<Number> &      dst,
1757                    const LinearAlgebra::distributed::Vector<Number> &src) const
1758 {
1759   using VectorizedArrayType = VectorizedArray<Number>;
1760 
1761   const unsigned int n_lanes = VectorizedArrayType::size();
1762 
1763   this->vec_fine.copy_locally_owned_data_from(src);
1764   this->vec_fine.update_ghost_values();
1765 
1766   this->vec_coarse.copy_locally_owned_data_from(dst);
1767 
1768   AlignedVector<VectorizedArrayType> evaluation_data_fine;
1769   AlignedVector<VectorizedArrayType> evaluation_data_coarse;
1770 
1771   for (const auto &scheme : schemes)
1772     {
1773       // identity -> take short cut and work directly on global vectors
1774       if (scheme.degree_fine == scheme.degree_coarse)
1775         {
1776           const unsigned int *indices_fine =
1777             scheme.level_dof_indices_fine.data();
1778           const unsigned int *indices_coarse =
1779             scheme.level_dof_indices_coarse.data();
1780           const Number *weights = nullptr;
1781 
1782           if (scheme.fine_element_is_continuous)
1783             weights = scheme.weights.data();
1784 
1785           for (unsigned int cell = 0; cell < scheme.n_coarse_cells; ++cell)
1786             {
1787               for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1788                 constraint_coarse.distribute_local_to_global( // TODO?
1789                   partitioner_coarse->local_to_global(indices_coarse[i]),
1790                   this->vec_fine.local_element(indices_fine[i]) *
1791                     (scheme.fine_element_is_continuous ? weights[i] : 1.0),
1792                   this->vec_coarse);
1793 
1794               indices_fine += scheme.dofs_per_cell_fine;
1795               indices_coarse += scheme.dofs_per_cell_coarse;
1796 
1797               if (scheme.fine_element_is_continuous)
1798                 weights += scheme.dofs_per_cell_fine;
1799             }
1800 
1801           continue;
1802         }
1803 
1804       // general case -> local restriction is needed
1805       evaluation_data_fine.resize(scheme.dofs_per_cell_fine);
1806       evaluation_data_coarse.resize(scheme.dofs_per_cell_fine);
1807 
1808       CellTransferFactory cell_transfer(scheme.degree_fine,
1809                                         scheme.degree_coarse);
1810 
1811       const unsigned int n_scalar_dofs_fine =
1812         Utilities::pow(scheme.degree_fine + 1, dim);
1813       const unsigned int n_scalar_dofs_coarse =
1814         Utilities::pow(scheme.degree_coarse + 1, dim);
1815 
1816       for (unsigned int cell = 0; cell < scheme.n_coarse_cells; cell += n_lanes)
1817         {
1818           const unsigned int n_lanes_filled =
1819             (cell + n_lanes > scheme.n_coarse_cells) ?
1820               (scheme.n_coarse_cells - cell) :
1821               n_lanes;
1822 
1823           // read from source vector and weight
1824           {
1825             const unsigned int *indices =
1826               &scheme.level_dof_indices_fine[cell * scheme.dofs_per_cell_fine];
1827             const Number *weights = nullptr;
1828 
1829             if (scheme.fine_element_is_continuous)
1830               weights = &scheme.weights[cell * scheme.dofs_per_cell_fine];
1831 
1832             for (unsigned int v = 0; v < n_lanes_filled; ++v)
1833               {
1834                 for (unsigned int i = 0; i < scheme.dofs_per_cell_fine; ++i)
1835                   evaluation_data_fine[i][v] =
1836                     this->vec_fine.local_element(indices[i]) *
1837                     (scheme.fine_element_is_continuous ? weights[i] : 1.0);
1838 
1839                 indices += scheme.dofs_per_cell_fine;
1840 
1841                 if (scheme.fine_element_is_continuous)
1842                   weights += scheme.dofs_per_cell_fine;
1843               }
1844           }
1845 
1846           // ------------------------------ fine -----------------------------
1847           for (int c = n_components - 1; c >= 0; --c)
1848             {
1849               CellRestrictor<dim, VectorizedArrayType> cell_restrictor(
1850                 scheme.prolongation_matrix_1d,
1851                 evaluation_data_fine.begin() + c * n_scalar_dofs_fine,
1852                 evaluation_data_coarse.begin() + c * n_scalar_dofs_coarse);
1853 
1854               cell_transfer.run(cell_restrictor);
1855             }
1856           // ----------------------------- coarse ----------------------------
1857 
1858 
1859           // write into dst vector
1860           {
1861             const unsigned int *indices =
1862               &scheme
1863                  .level_dof_indices_coarse[cell * scheme.dofs_per_cell_coarse];
1864             for (unsigned int v = 0; v < n_lanes_filled; ++v)
1865               {
1866                 for (unsigned int i = 0; i < scheme.dofs_per_cell_coarse; ++i)
1867                   constraint_coarse.distribute_local_to_global(
1868                     partitioner_coarse->local_to_global(indices[i]),
1869                     evaluation_data_coarse[i][v],
1870                     this->vec_coarse);
1871                 indices += scheme.dofs_per_cell_coarse;
1872               }
1873           }
1874         }
1875     }
1876 
1877   if (schemes.size() && schemes.front().fine_element_is_continuous)
1878     this->vec_coarse.compress(VectorOperation::add);
1879 
1880   dst.copy_locally_owned_data_from(this->vec_coarse);
1881 }
1882 
1883 
1884 
1885 template <int dim, typename Number>
1886 void
1887 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
reinit_geometric_transfer(const DoFHandler<dim> & dof_handler_fine,const DoFHandler<dim> & dof_handler_coarse,const AffineConstraints<Number> & constraint_fine,const AffineConstraints<Number> & constraint_coarse)1888   reinit_geometric_transfer(const DoFHandler<dim> &          dof_handler_fine,
1889                             const DoFHandler<dim> &          dof_handler_coarse,
1890                             const AffineConstraints<Number> &constraint_fine,
1891                             const AffineConstraints<Number> &constraint_coarse)
1892 {
1893   internal::MGTwoLevelTransferImplementation::reinit_geometric_transfer(
1894     dof_handler_fine,
1895     dof_handler_coarse,
1896     constraint_fine,
1897     constraint_coarse,
1898     *this);
1899 }
1900 
1901 
1902 
1903 template <int dim, typename Number>
1904 void
1905 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
reinit_polynomial_transfer(const DoFHandler<dim> & dof_handler_fine,const DoFHandler<dim> & dof_handler_coarse,const AffineConstraints<Number> & constraint_fine,const AffineConstraints<Number> & constraint_coarse)1906   reinit_polynomial_transfer(const DoFHandler<dim> &dof_handler_fine,
1907                              const DoFHandler<dim> &dof_handler_coarse,
1908                              const AffineConstraints<Number> &constraint_fine,
1909                              const AffineConstraints<Number> &constraint_coarse)
1910 {
1911   internal::MGTwoLevelTransferImplementation::reinit_polynomial_transfer(
1912     dof_handler_fine,
1913     dof_handler_coarse,
1914     constraint_fine,
1915     constraint_coarse,
1916     *this);
1917 }
1918 
1919 
1920 
1921 template <int dim, typename Number>
1922 bool
1923 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
fast_polynomial_transfer_supported(const unsigned int fe_degree_fine,const unsigned int fe_degree_coarse)1924   fast_polynomial_transfer_supported(const unsigned int fe_degree_fine,
1925                                      const unsigned int fe_degree_coarse)
1926 {
1927   CellTransferFactory cell_transfer(fe_degree_fine, fe_degree_coarse);
1928   CellProlongatorTest cell_transfer_test;
1929 
1930   return cell_transfer.run(cell_transfer_test);
1931 }
1932 
1933 DEAL_II_NAMESPACE_CLOSE
1934 
1935 #endif
1936