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 #ifndef dealii_mg_transfer_global_coarsening_h
17 #define dealii_mg_transfer_global_coarsening_h
18 
19 #include <deal.II/base/mg_level_object.h>
20 
21 #include <deal.II/dofs/dof_handler.h>
22 
23 #include <deal.II/lac/affine_constraints.h>
24 #include <deal.II/lac/la_parallel_vector.h>
25 
26 #include <deal.II/multigrid/mg_base.h>
27 
28 DEAL_II_NAMESPACE_OPEN
29 
30 // Forward declarations
31 #ifndef DOXYGEN
32 namespace internal
33 {
34   class MGTwoLevelTransferImplementation;
35 }
36 #endif
37 
38 
39 
40 /**
41  * Class for transfer between two multigrid levels for p or global coarsening.
42  */
43 template <int dim, typename VectorType>
44 class MGTwoLevelTransfer
45 {
46 public:
47   /**
48    * Perform prolongation.
49    */
50   void
51   prolongate(VectorType &dst, const VectorType &src) const;
52 
53   /**
54    * Perform restriction.
55    */
56   void
57   restrict_and_add(VectorType &dst, const VectorType &src) const;
58 };
59 
60 
61 
62 /**
63  * Class for transfer between two multigrid levels for p or global coarsening.
64  * Specialization for LinearAlgebra::distributed::Vector.
65  */
66 template <int dim, typename Number>
67 class MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>
68 {
69 public:
70   /**
71    * Set up global coarsening transfer @p transfer between the given
72    * dof-handlers.
73    */
74   void
75   reinit_geometric_transfer(const DoFHandler<dim> &          dof_handler_fine,
76                             const DoFHandler<dim> &          dof_handler_coarse,
77                             const AffineConstraints<Number> &constraint_fine,
78                             const AffineConstraints<Number> &constraint_coarse);
79 
80   /**
81    * Set up polynomial coarsening transfer @p transfer between the given
82    * dof-handlers.
83    *
84    * @note The function polynomial_transfer_supported() can be used to
85    *   check if the given polynomial coarsening strategy is supported.
86    */
87   void
88   reinit_polynomial_transfer(
89     const DoFHandler<dim> &          dof_handler_fine,
90     const DoFHandler<dim> &          dof_handler_coarse,
91     const AffineConstraints<Number> &constraint_fine,
92     const AffineConstraints<Number> &constraint_coarse);
93 
94   /**
95    * Check if a fast templated version of the polynomial transfer between
96    * @p fe_degree_fine and @p fe_degree_coarse is available.
97    *
98    * @note Currently, the polynomial coarsening strategies: 1) go-to-one,
99    *   2) bisect, and 3) decrease-by-one are precompiled with templates for
100    *   degrees up to 9.
101    */
102   static bool
103   fast_polynomial_transfer_supported(const unsigned int fe_degree_fine,
104                                      const unsigned int fe_degree_coarse);
105 
106   /**
107    * Perform prolongation.
108    */
109   void
110   prolongate(LinearAlgebra::distributed::Vector<Number> &      dst,
111              const LinearAlgebra::distributed::Vector<Number> &src) const;
112 
113   /**
114    * Perform restriction.
115    */
116   void
117   restrict_and_add(LinearAlgebra::distributed::Vector<Number> &      dst,
118                    const LinearAlgebra::distributed::Vector<Number> &src) const;
119 
120   /**
121    * Print internal data structures to stream @p out.
122    */
123   template <typename Stream>
124   void
125   print_internal(Stream &out) const;
126 
127 private:
128   /**
129    * A multigrid transfer scheme. A multrigrid transfer class can have different
130    * transfer schemes to enable p-adaptivity (one transfer scheme per
131    * polynomial degree pair) and to enable global coarsening (one transfer
132    * scheme for transfer between children and parent cells, as well as, one
133    * transfer scheme for cells that are not refined).
134    */
135   struct MGTransferScheme
136   {
137     /**
138      * Number of coarse cells.
139      */
140     unsigned int n_coarse_cells;
141 
142     /**
143      * Number of degrees of freedom of a coarse cell.
144      */
145     unsigned int dofs_per_cell_coarse;
146 
147     /**
148      * Number of degrees of freedom of fine cell.
149      */
150     unsigned int dofs_per_cell_fine;
151 
152     /**
153      * Polynomial degree of the finite element of the coarse cells.
154      */
155     unsigned int degree_coarse;
156 
157     /**
158      * Polynomial degree of the finite element of the fine cells.
159      */
160     unsigned int degree_fine;
161 
162     /**
163      * Flag if the finite element on the fine cells are continuous. If yes,
164      * the multiplicity of DoF sharing a vertex/line as well as constraints have
165      * to be taken in account via weights.
166      */
167     bool fine_element_is_continuous;
168 
169     /**
170      * Weights for continuous elements.
171      */
172     std::vector<Number> weights;
173 
174     /**
175      * 1D prolongation matrix.
176      */
177     AlignedVector<VectorizedArray<Number>> prolongation_matrix_1d;
178 
179     /**
180      * DoF indices of the coarse cells, expressed in indices local to the MPI
181      * rank.
182      */
183     std::vector<unsigned int> level_dof_indices_coarse;
184 
185     /**
186      * DoF indices of the fine cells, expressed in indices local to the MPI
187      * rank.
188      */
189     std::vector<unsigned int> level_dof_indices_fine;
190 
191     /**
192      * Print internal data structures to stream @p out.
193      */
194     template <typename Stream>
195     void
196     print(Stream &out) const;
197   };
198 
199   /**
200    * Transfer schemes.
201    */
202   std::vector<MGTransferScheme> schemes;
203 
204   /**
205    * Partitioner needed by the intermediate vector.
206    */
207   std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_fine;
208 
209   /**
210    * Partitioner needed by the intermediate vector.
211    */
212   std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_coarse;
213 
214   /**
215    * Internal vector needed for collecting all degrees of freedom of the
216    * fine cells.
217    */
218   mutable LinearAlgebra::distributed::Vector<Number> vec_fine;
219 
220   /**
221    * Internal vector on that the actual prolongation/restriction is performed.
222    */
223   mutable LinearAlgebra::distributed::Vector<Number> vec_coarse;
224 
225   /**
226    * Constraint matrix on coarse level.
227    */
228   AffineConstraints<Number> constraint_coarse;
229 
230   /**
231    * Number of components.
232    */
233   unsigned int n_components;
234 
235   friend class internal::MGTwoLevelTransferImplementation;
236 };
237 
238 
239 
240 /**
241  * Implementation of the MGTransferBase. In contrast to
242  * other multigrid transfer operators, the user can provide separate
243  * transfer operators of type MGTwoLevelTransfer between each level.
244  *
245  * This class currently only works for tensor-product finite elements based on
246  * FE_Q and FE_DGQ elements. Systems involving multiple components of
247  * one of these element, as well as, systems with different elements or other
248  * elements are currently not implemented.
249  */
250 template <typename MatrixType, typename VectorType>
251 class MGTransferGlobalCoarsening : public dealii::MGTransferBase<VectorType>
252 {
253 public:
254   static_assert(std::is_same<typename MatrixType::value_type,
255                              typename VectorType::value_type>::value,
256                 "Types do not match.");
257 
258   /**
259    * Dimension.
260    */
261   static const int dim = MatrixType::dim;
262 
263   /**
264    * Value type.
265    */
266   using Number = typename MatrixType::value_type;
267 
268   /**
269    * Constructor taking an operator for each level (minimum requirement is
270    * that the operator provides the function initialize_dof_vector()) and
271    * transfer operators (with the coarsest level kept empty in @p transfer).
272    */
273   MGTransferGlobalCoarsening(
274     const MGLevelObject<MatrixType> &                         matrices,
275     const MGLevelObject<MGTwoLevelTransfer<dim, VectorType>> &transfer);
276 
277   /**
278    * Perform prolongation.
279    */
280   void
281   prolongate(const unsigned int to_level,
282              VectorType &       dst,
283              const VectorType & src) const;
284 
285   /**
286    * Perform restriction.
287    */
288   virtual void
289   restrict_and_add(const unsigned int from_level,
290                    VectorType &       dst,
291                    const VectorType & src) const;
292 
293   /**
294    * Initialize internal vectors and copy @p src vector to the finest
295    * multigrid level.
296    *
297    * @note DoFHandler is not needed here, but is required by the interface.
298    */
299   template <class InVector, int spacedim>
300   void
301   copy_to_mg(const DoFHandler<dim, spacedim> &dof_handler,
302              MGLevelObject<VectorType> &      dst,
303              const InVector &                 src) const;
304 
305   /**
306    * Initialize internal vectors and copy the values on the finest
307    * multigrid level to @p dst vector.
308    *
309    * @note DoFHandler is not needed here, but is required by the interface.
310    */
311   template <class OutVector, int spacedim>
312   void
313   copy_from_mg(const DoFHandler<dim, spacedim> &dof_handler,
314                OutVector &                      dst,
315                const MGLevelObject<VectorType> &src) const;
316 
317 private:
318   const MGLevelObject<MatrixType> &                         matrices;
319   const MGLevelObject<MGTwoLevelTransfer<dim, VectorType>> &transfer;
320 };
321 
322 
323 
324 #ifndef DOXYGEN
325 
326 /* ----------------------- Inline functions --------------------------------- */
327 
328 
329 
330 template <int dim, typename Number>
331 template <typename Stream>
332 void
333 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
print(Stream & out)334   MGTransferScheme::print(Stream &out) const
335 {
336   out << "weights:" << std::endl;
337   for (const auto w : weights)
338     out << w << " ";
339   out << std::endl;
340 
341   out << "level_dof_indices_fine:" << std::endl;
342   for (const auto w : level_dof_indices_fine)
343     out << w << " ";
344   out << std::endl;
345 
346   out << "level_dof_indices_coarse:" << std::endl;
347   for (const auto w : level_dof_indices_coarse)
348     out << w << " ";
349   out << std::endl;
350 
351   out << "prolongation_matrix_1d:" << std::endl;
352   for (const auto w : prolongation_matrix_1d)
353     out << w[0] << " ";
354   out << std::endl;
355 }
356 
357 
358 
359 template <int dim, typename Number>
360 template <typename Stream>
361 void
362 MGTwoLevelTransfer<dim, LinearAlgebra::distributed::Vector<Number>>::
print_internal(Stream & out)363   print_internal(Stream &out) const
364 {
365   for (const auto &scheme : schemes)
366     scheme.print(out);
367 }
368 
369 
370 
371 template <typename MatrixType, typename VectorType>
MGTransferGlobalCoarsening(const MGLevelObject<MatrixType> & matrices,const MGLevelObject<MGTwoLevelTransfer<dim,VectorType>> & transfer)372 MGTransferGlobalCoarsening<MatrixType, VectorType>::MGTransferGlobalCoarsening(
373   const MGLevelObject<MatrixType> &                         matrices,
374   const MGLevelObject<MGTwoLevelTransfer<dim, VectorType>> &transfer)
375   : matrices(matrices)
376   , transfer(transfer)
377 {
378   AssertDimension(matrices.max_level() - matrices.min_level(),
379                   transfer.max_level() - transfer.min_level());
380 }
381 
382 
383 
384 template <typename MatrixType, typename VectorType>
385 void
prolongate(const unsigned int to_level,VectorType & dst,const VectorType & src)386 MGTransferGlobalCoarsening<MatrixType, VectorType>::prolongate(
387   const unsigned int to_level,
388   VectorType &       dst,
389   const VectorType & src) const
390 {
391   this->transfer[to_level].prolongate(dst, src);
392 }
393 
394 
395 
396 template <typename MatrixType, typename VectorType>
397 void
restrict_and_add(const unsigned int from_level,VectorType & dst,const VectorType & src)398 MGTransferGlobalCoarsening<MatrixType, VectorType>::restrict_and_add(
399   const unsigned int from_level,
400   VectorType &       dst,
401   const VectorType & src) const
402 {
403   this->transfer[from_level].restrict_and_add(dst, src);
404 }
405 
406 
407 
408 template <typename MatrixType, typename VectorType>
409 template <class InVector, int spacedim>
410 void
copy_to_mg(const DoFHandler<dim,spacedim> & dof_handler,MGLevelObject<VectorType> & dst,const InVector & src)411 MGTransferGlobalCoarsening<MatrixType, VectorType>::copy_to_mg(
412   const DoFHandler<dim, spacedim> &dof_handler,
413   MGLevelObject<VectorType> &      dst,
414   const InVector &                 src) const
415 {
416   (void)dof_handler;
417 
418   for (unsigned int level = dst.min_level(); level <= dst.max_level(); ++level)
419     matrices[level].initialize_dof_vector(dst[level]);
420 
421   dst[dst.max_level()].copy_locally_owned_data_from(src);
422 }
423 
424 
425 
426 template <typename MatrixType, typename VectorType>
427 template <class OutVector, int spacedim>
428 void
copy_from_mg(const DoFHandler<dim,spacedim> & dof_handler,OutVector & dst,const MGLevelObject<VectorType> & src)429 MGTransferGlobalCoarsening<MatrixType, VectorType>::copy_from_mg(
430   const DoFHandler<dim, spacedim> &dof_handler,
431   OutVector &                      dst,
432   const MGLevelObject<VectorType> &src) const
433 {
434   (void)dof_handler;
435 
436   dst.copy_locally_owned_data_from(src[src.max_level()]);
437 }
438 
439 #endif
440 
441 DEAL_II_NAMESPACE_CLOSE
442 
443 #endif
444