]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Use MGTransferGlobalCoarsening also for local smoothing 15794/head
authorPeter Munch <peterrmuench@gmail.com>
Sat, 15 Jul 2023 12:34:58 +0000 (14:34 +0200)
committerPeter Munch <peterrmuench@gmail.com>
Sat, 5 Aug 2023 12:19:08 +0000 (14:19 +0200)
107 files changed:
include/deal.II/multigrid/mg_transfer.h
include/deal.II/multigrid/mg_transfer_global_coarsening.h
include/deal.II/multigrid/mg_transfer_global_coarsening.templates.h
source/multigrid/mg_level_global_transfer.cc
source/multigrid/mg_transfer_global_coarsening.inst.in
tests/multigrid-global-coarsening/interpolate_to_mg.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/interpolate_to_mg_01.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/interpolate_to_mg_01.with_p4est=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/mg_data_out_04.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/mg_data_out_04.with_p4est=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/mg_data_out_05.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/mg_data_out_05.with_p4est=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_periodic.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_sip_01.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_sip_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/multigrid_dg_sip_02.with_lapack=true.with_p4est=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.with_p4est=true.with_lapack=true.mpirun=4.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.with_p4est=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.with_p4est=true.with_lapack=true.mpirun=4.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.with_p4est=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.with_lapack=true.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_interleave.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_interleave.with_p4est=true.with_lapack=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.with_p4est=true.with_lapack=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_mf.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_mf.with_p4est=true.with_lapack=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_mf_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/parallel_multigrid_mf_02.with_p4est=true.with_lapack=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/step-37-inhomogeneous-1.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/step-37-inhomogeneous-1.with_lapack=true.mpirun=4.with_p4est=true.output [new file with mode: 0644]
tests/multigrid-global-coarsening/stokes_computation.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/stokes_computation.with_lapack=true.with_p4est=true.mpirun=4.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_05.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_05.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_06.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_06.with_p4est=true.mpirun=3.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_01.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=4.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02_block.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02_block.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_03.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_03.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_04.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=4.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=7.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_05.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_06.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=10.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_07.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_07.with_p4est=true.with_trilinos=true.mpirun=5.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_08.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_08.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_09.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_09.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_10.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_10.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_11.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_11.with_p4est=true.with_trilinos=true.mpirun=1.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_12.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_12.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_14.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_matrix_free_14.with_p4est=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_prebuilt_04.cc [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=2.output [new file with mode: 0644]
tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=3.output [new file with mode: 0644]

index 6f7c7e6071f43abea8e52eaa71e6ca6712a593c3..a4740892eb815661d1ed42fca41f882a1fc1681a 100644 (file)
@@ -386,8 +386,7 @@ protected:
   /**
    * The mg_constrained_dofs of the level systems.
    */
-  SmartPointer<const MGConstrainedDoFs, MGLevelGlobalTransfer<VectorType>>
-    mg_constrained_dofs;
+  SmartPointer<const MGConstrainedDoFs> mg_constrained_dofs;
 
 private:
   /**
@@ -575,10 +574,7 @@ protected:
   /**
    * The mg_constrained_dofs of the level systems.
    */
-  SmartPointer<
-    const MGConstrainedDoFs,
-    MGLevelGlobalTransfer<LinearAlgebra::distributed::Vector<Number>>>
-    mg_constrained_dofs;
+  SmartPointer<const MGConstrainedDoFs> mg_constrained_dofs;
 
   /**
    * In the function copy_to_mg, we need to access ghosted entries of the
index 3a72e69c9c73d1cab58a576a14751de9dec5e57a..bd58012b31f978123e0ae98483b486c4426fdc69 100644 (file)
@@ -320,6 +320,7 @@ protected:
    */
   bool fine_element_is_continuous;
 
+public:
   /**
    * Partitioner needed by the intermediate vector.
    */
@@ -330,6 +331,7 @@ protected:
    */
   std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_fine;
 
+protected:
   /**
    * Internal vector needed for collecting all degrees of freedom of the fine
    * cells. It is only initialized if the fine-level DoF indices touch DoFs
@@ -831,19 +833,22 @@ private:
  *
  * The implementation of this class is explained in detail in @cite munch2022gc.
  */
-template <int dim, typename VectorType>
-class MGTransferGlobalCoarsening : public dealii::MGTransferBase<VectorType>
+template <int dim, typename Number>
+class MGTransferMF : public dealii::MGLevelGlobalTransfer<
+                       LinearAlgebra::distributed::Vector<Number>>
 {
 public:
   /**
    * Value type.
    */
-  using Number = typename VectorType::value_type;
+  using VectorType = LinearAlgebra::distributed::Vector<Number>;
 
   /**
    * Default constructor.
+   *
+   * @note See also MGTransferMatrixFree.
    */
-  MGTransferGlobalCoarsening() = default;
+  MGTransferMF() = default;
 
   /**
    * @name Global coarsening.
@@ -860,10 +865,9 @@ public:
    * std::unique_ptr to the actual transfer operator.
    */
   template <typename MGTwoLevelTransferObject>
-  MGTransferGlobalCoarsening(
-    const MGLevelObject<MGTwoLevelTransferObject> &transfer,
-    const std::function<void(const unsigned int, VectorType &)>
-      &initialize_dof_vector = {});
+  MGTransferMF(const MGLevelObject<MGTwoLevelTransferObject> &transfer,
+               const std::function<void(const unsigned int, VectorType &)>
+                 &initialize_dof_vector = {});
 
   /**
    * Set two-level transfers.
@@ -906,7 +910,7 @@ public:
    *
    * @note See also MGTransferMatrixFree.
    */
-  MGTransferGlobalCoarsening(const MGConstrainedDoFs &mg_constrained_dofs);
+  MGTransferMF(const MGConstrainedDoFs &mg_constrained_dofs);
 
   /**
    * Initialize the constraints to be used in build().
@@ -1011,7 +1015,7 @@ public:
   /**
    * Like the above function but with a user-provided DoFHandler as
    * additional argument. However, this DoFHandler is not used internally, but
-   * is required to be able to use MGTransferGlobalCoarsening and
+   * is required to be able to use MGTransferMF and
    * MGTransferMatrixFree as template argument.
    */
   template <class InVector>
@@ -1048,6 +1052,13 @@ public:
   unsigned int
   max_level() const;
 
+  /**
+   * Clear all data fields and brings the class into a condition similar
+   * to after having called the default constructor.
+   */
+  void
+  clear();
+
   /** @} */
 
 private:
@@ -1072,15 +1083,12 @@ private:
   /**
    * Function to initialize internal level vectors.
    */
+  template <class InVector>
   void
-  initialize_dof_vector(const unsigned int level, VectorType &vector) const;
-
-  /**
-   * MGConstrainedDoFs passed during build().
-   *
-   * @note See also MGTransferMatrixFree.
-   */
-  SmartPointer<const MGConstrainedDoFs> mg_constrained_dofs;
+  initialize_dof_vector(const unsigned int level,
+                        VectorType &       vector,
+                        const InVector &   vector_reference,
+                        const bool         omit_zeroing_entries) const;
 
   /**
    * Internal transfer operator.
@@ -1106,44 +1114,109 @@ private:
 /**
  * This class works with LinearAlgebra::distributed::BlockVector and
  * performs exactly the same transfer operations for each block as
- * MGTransferGlobalCoarsening.
+ * MGTransferMF.
  */
-template <int dim, typename VectorType>
-class MGTransferBlockGlobalCoarsening
-  : public MGTransferBlockMatrixFreeBase<
-      dim,
-      typename VectorType::value_type,
-      MGTransferGlobalCoarsening<dim, VectorType>>
+template <int dim, typename Number>
+class MGTransferBlockMF
+  : public MGTransferBlockMatrixFreeBase<dim, Number, MGTransferMF<dim, Number>>
 {
 public:
   /**
    * Constructor.
    */
-  MGTransferBlockGlobalCoarsening(
-    const MGTransferGlobalCoarsening<dim, VectorType> &transfer_operator);
+  MGTransferBlockMF(const MGTransferMF<dim, Number> &transfer_operator);
+
+  /**
+   * Constructor.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  MGTransferBlockMF() = default;
+
+  /**
+   * Constructor.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  MGTransferBlockMF(const MGConstrainedDoFs &mg_constrained_dofs);
+
+  /**
+   * Constructor.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  MGTransferBlockMF(const std::vector<MGConstrainedDoFs> &mg_constrained_dofs);
+
+  /**
+   * Initialize the constraints to be used in build().
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  void
+  initialize_constraints(const MGConstrainedDoFs &mg_constrained_dofs);
+
+  /**
+   * Same as above for the case that each block has its own DoFHandler.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  void
+  initialize_constraints(
+    const std::vector<MGConstrainedDoFs> &mg_constrained_dofs);
+
+  /**
+   * Actually build the information for the prolongation for each level.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  void
+  build(const DoFHandler<dim> &dof_handler);
+
+  /**
+   * Same as above for the case that each block has its own DoFHandler.
+   *
+   * @note See also MGTransferBlockMatrixFree.
+   */
+  void
+  build(const std::vector<const DoFHandler<dim> *> &dof_handler);
 
 protected:
-  const MGTransferGlobalCoarsening<dim, VectorType> &
+  const MGTransferMF<dim, Number> &
   get_matrix_free_transfer(const unsigned int b) const override;
 
 private:
+  /**
+   * Internal non-block version of transfer operation.
+   */
+  std::vector<MGTransferMF<dim, Number>> transfer_operators_internal;
+
   /**
    * Non-block version of transfer operation.
    */
-  const MGTransferGlobalCoarsening<dim, VectorType> &transfer_operator;
+  std::vector<SmartPointer<const MGTransferMF<dim, Number>>> transfer_operators;
 };
 
 
 
+template <int dim, typename VectorType>
+using MGTransferGlobalCoarsening =
+  MGTransferMF<dim, typename VectorType::value_type>;
+
+template <int dim, typename VectorType>
+using MGTransferBlockGlobalCoarsening =
+  MGTransferBlockMF<dim, typename VectorType::value_type>;
+
+
+
 #ifndef DOXYGEN
 
 /* ----------------------- Inline functions --------------------------------- */
 
 
 
-template <int dim, typename VectorType>
+template <int dim, typename Number>
 template <typename MGTwoLevelTransferObject>
-MGTransferGlobalCoarsening<dim, VectorType>::MGTransferGlobalCoarsening(
+MGTransferMF<dim, Number>::MGTransferMF(
   const MGLevelObject<MGTwoLevelTransferObject> &transfer,
   const std::function<void(const unsigned int, VectorType &)>
     &initialize_dof_vector)
@@ -1154,19 +1227,10 @@ MGTransferGlobalCoarsening<dim, VectorType>::MGTransferGlobalCoarsening(
 
 
 
-template <int dim, typename VectorType>
-MGTransferGlobalCoarsening<dim, VectorType>::MGTransferGlobalCoarsening(
-  const MGConstrainedDoFs &mg_constrained_dofs)
-{
-  this->initialize_constraints(mg_constrained_dofs);
-}
-
-
-
-template <int dim, typename VectorType>
+template <int dim, typename Number>
 template <typename MGTwoLevelTransferObject>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::intitialize_two_level_transfers(
+MGTransferMF<dim, Number>::intitialize_two_level_transfers(
   const MGLevelObject<MGTwoLevelTransferObject> &transfer)
 {
   this->intitialize_transfer_references(transfer);
@@ -1174,52 +1238,10 @@ MGTransferGlobalCoarsening<dim, VectorType>::intitialize_two_level_transfers(
 
 
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::initialize_constraints(
-  const MGConstrainedDoFs &mg_constrained_dofs)
-{
-  this->mg_constrained_dofs = &mg_constrained_dofs;
-}
-
-
-
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::intitialize_internal_transfer(
-  const DoFHandler<dim> &                      dof_handler,
-  const SmartPointer<const MGConstrainedDoFs> &mg_constrained_dofs)
-{
-  const unsigned int min_level = 0;
-  const unsigned int max_level =
-    dof_handler.get_triangulation().n_global_levels() - 1;
-
-  MGLevelObject<AffineConstraints<typename VectorType::value_type>> constraints(
-    min_level, max_level);
-
-  if (mg_constrained_dofs)
-    for (unsigned int l = min_level; l <= max_level; ++l)
-      mg_constrained_dofs->merge_constraints(
-        constraints[l],
-        l,
-        /*add_boundary_indices*/ true,
-        /*add_refinement_edge_indices*/ false,
-        /*add_level_constraints*/ true,
-        /*add_user_constraints*/ true);
-
-  this->internal_transfer.resize(min_level, max_level);
-
-  for (unsigned int l = min_level; l < max_level; ++l)
-    internal_transfer[l + 1].reinit_geometric_transfer(
-      dof_handler, dof_handler, constraints[l + 1], constraints[l], l + 1, l);
-}
-
-
-
-template <int dim, typename VectorType>
+template <int dim, typename Number>
 template <typename MGTwoLevelTransferObject>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::intitialize_transfer_references(
+MGTransferMF<dim, Number>::intitialize_transfer_references(
   const MGLevelObject<MGTwoLevelTransferObject> &transfer)
 {
   const unsigned int min_level = transfer.min_level();
@@ -1235,190 +1257,171 @@ MGTransferGlobalCoarsening<dim, VectorType>::intitialize_transfer_references(
 
 
 
-template <int dim, typename VectorType>
+template <int dim, typename Number>
+template <class InVector>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::build(
-  const std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
-    &external_partitioners)
+MGTransferMF<dim, Number>::initialize_dof_vector(
+  const unsigned int level,
+  VectorType &       vec,
+  const InVector &   vec_reference,
+  const bool         omit_zeroing_entries) const
 {
-  this->external_partitioners = external_partitioners;
+  std::shared_ptr<const Utilities::MPI::Partitioner> partitioner;
 
-  if (this->external_partitioners.size() > 0)
+  if (external_partitioners.empty())
     {
-      const unsigned int min_level = transfer.min_level();
-      const unsigned int max_level = transfer.max_level();
-
-      AssertDimension(this->external_partitioners.size(), transfer.n_levels());
-
-      for (unsigned int l = min_level + 1; l <= max_level; ++l)
-        transfer[l]->enable_inplace_operations_if_possible(
-          this->external_partitioners[l - 1 - min_level],
-          this->external_partitioners[l - min_level]);
+      partitioner = vec_reference.get_partitioner();
     }
-}
-
-
-
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::build(
-  const std::function<void(const unsigned int, VectorType &)>
-    &initialize_dof_vector)
-{
-  if (initialize_dof_vector)
+  else
     {
-      const unsigned int min_level = transfer.min_level();
-      const unsigned int max_level = transfer.max_level();
-      const unsigned int n_levels  = transfer.n_levels();
+      Assert(transfer.min_level() <= level && level <= transfer.max_level(),
+             ExcInternalError());
 
-      std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
-        external_partitioners(n_levels);
+      partitioner = external_partitioners[level - transfer.min_level()];
+    }
 
-      for (unsigned int l = min_level; l <= max_level; ++l)
-        {
-          LinearAlgebra::distributed::Vector<typename VectorType::value_type>
-            vector;
-          initialize_dof_vector(l, vector);
-          external_partitioners[l - min_level] = vector.get_partitioner();
-        }
+  // check if vectors are already correctly initalized
 
-      this->build(external_partitioners);
-    }
-  else
+  // yes: same partitioners are used
+  if (vec.get_partitioner().get() == partitioner.get())
     {
-      this->build();
+      if (omit_zeroing_entries == false)
+        vec = 0;
+      return; // nothing to do
     }
-}
-
 
+  // yes: vectors are compatible
+  if (vec.size() == partitioner->size() &&
+      vec.locally_owned_size() == partitioner->locally_owned_size())
+    {
+      if (omit_zeroing_entries == false)
+        vec = 0;
+      return; // nothing to do
+    }
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::build(
-  const DoFHandler<dim> &dof_handler,
-  const std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
-    &external_partitioners)
-{
-  this->intitialize_internal_transfer(dof_handler, mg_constrained_dofs);
-  this->intitialize_transfer_references(internal_transfer);
-  this->build(external_partitioners);
+  // no
+  vec.reinit(partitioner, omit_zeroing_entries);
 }
 
 
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::build(
-  const DoFHandler<dim> &dof_handler,
-  const std::function<void(const unsigned int, VectorType &)>
-    &initialize_dof_vector)
-{
-  this->intitialize_internal_transfer(dof_handler, mg_constrained_dofs);
-  this->intitialize_transfer_references(internal_transfer);
-  this->build(initialize_dof_vector);
-}
-
-
-
-template <int dim, typename VectorType>
+template <int dim, typename Number>
+template <class InVector>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::initialize_dof_vector(
-  const unsigned int level,
-  VectorType &       vec) const
+MGTransferMF<dim, Number>::copy_to_mg(const DoFHandler<dim> &    dof_handler,
+                                      MGLevelObject<VectorType> &dst,
+                                      const InVector &           src) const
 {
-  AssertDimension(transfer.n_levels(), external_partitioners.size());
-  AssertIndexRange(level, transfer.max_level() + 1);
-
-  const auto &external_partitioner =
-    external_partitioners[level - transfer.min_level()];
-
-  if (vec.get_partitioner().get() != external_partitioner.get())
-    vec.reinit(external_partitioner);
-}
+  (void)dof_handler;
 
+  for (unsigned int level = dst.min_level(); level <= dst.max_level(); ++level)
+    {
+      const bool zero_out_values =
+        (this->perform_plain_copy == false &&
+         this->perform_renumbered_plain_copy == false) ||
+        level != dst.max_level();
 
+      this->initialize_dof_vector(level, dst[level], src, !zero_out_values);
+    }
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::prolongate(
-  const unsigned int to_level,
-  VectorType &       dst,
-  const VectorType & src) const
-{
-  dst = 0;
-  prolongate_and_add(to_level, dst, src);
-}
+  if (this->perform_plain_copy)
+    {
+      dst[dst.max_level()].copy_locally_owned_data_from(src);
+    }
+  else if (this->perform_renumbered_plain_copy)
+    {
+      auto &dst_level = dst[dst.max_level()];
 
+      for (unsigned int i = 0; i < this->copy_indices.back().n_cols(); ++i)
+        dst_level.local_element(this->copy_indices.back()(1, i)) =
+          src.local_element(i);
+    }
+  else
+    {
+      this->ghosted_global_vector = src;
+      this->ghosted_global_vector.update_ghost_values();
 
+      for (unsigned int l = dst.max_level() + 1; l != dst.min_level();)
+        {
+          --l;
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::prolongate_and_add(
-  const unsigned int to_level,
-  VectorType &       dst,
-  const VectorType & src) const
-{
-  this->transfer[to_level]->prolongate_and_add(dst, src);
-}
+          auto &dst_level = dst[l];
 
+          const auto copy_unknowns = [&](const auto &indices) {
+            for (unsigned int i = 0; i < indices.n_cols(); ++i)
+              dst_level.local_element(indices(1, i)) =
+                this->ghosted_global_vector.local_element(indices(0, i));
+          };
 
+          copy_unknowns(this->copy_indices[l]);
+          copy_unknowns(this->copy_indices_level_mine[l]);
 
-template <int dim, typename VectorType>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::restrict_and_add(
-  const unsigned int from_level,
-  VectorType &       dst,
-  const VectorType & src) const
-{
-  this->transfer[from_level]->restrict_and_add(dst, src);
+          dst_level.compress(VectorOperation::insert);
+        }
+    }
 }
 
 
 
-template <int dim, typename VectorType>
-template <class InVector>
+template <int dim, typename Number>
+template <class OutVector>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::copy_to_mg(
-  const DoFHandler<dim> &    dof_handler,
-  MGLevelObject<VectorType> &dst,
-  const InVector &           src) const
+MGTransferMF<dim, Number>::copy_from_mg(
+  const DoFHandler<dim> &          dof_handler,
+  OutVector &                      dst,
+  const MGLevelObject<VectorType> &src) const
 {
   (void)dof_handler;
 
-  for (unsigned int level = dst.min_level(); level <= dst.max_level(); ++level)
+  if (this->perform_plain_copy)
     {
-      initialize_dof_vector(level, dst[level]);
-
-      if (level == dst.max_level())
-        dst[level].copy_locally_owned_data_from(src);
-      else
-        dst[level] = 0.0;
+      dst.zero_out_ghost_values();
+      dst.copy_locally_owned_data_from(src[src.max_level()]);
     }
-}
+  else if (this->perform_renumbered_plain_copy)
+    {
+      const auto &src_level = src[src.max_level()];
+      dst.zero_out_ghost_values();
+      for (unsigned int i = 0; i < this->copy_indices.back().n_cols(); ++i)
+        dst.local_element(i) =
+          src_level.local_element(this->copy_indices.back()(1, i));
+    }
+  else
+    {
+      dst = 0;
+      for (unsigned int l = src.min_level(); l <= src.max_level(); ++l)
+        {
+          auto &ghosted_vector = this->ghosted_level_vector[l];
 
+          if (this->ghosted_level_vector[l].size() > 0)
+            ghosted_vector = src[l];
 
+          const auto *const ghosted_vector_ptr =
+            (this->ghosted_level_vector[l].size() > 0) ? &ghosted_vector :
+                                                         &src[l];
 
-template <int dim, typename VectorType>
-template <class OutVector>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::copy_from_mg(
-  const DoFHandler<dim> &          dof_handler,
-  OutVector &                      dst,
-  const MGLevelObject<VectorType> &src) const
-{
-  (void)dof_handler;
+          ghosted_vector_ptr->update_ghost_values();
+
+          const auto copy_unknowns = [&](const auto &indices) {
+            for (unsigned int i = 0; i < indices.n_cols(); ++i)
+              dst.local_element(indices(0, i)) =
+                ghosted_vector_ptr->local_element(indices(1, i));
+          };
 
-  dst.copy_locally_owned_data_from(src[src.max_level()]);
+          copy_unknowns(this->copy_indices[l]);
+          copy_unknowns(this->copy_indices_global_mine[l]);
+        }
+      dst.compress(VectorOperation::insert);
+    }
 }
 
 
 
-template <int dim, typename VectorType>
+template <int dim, typename Number>
 template <class InVector>
 void
-MGTransferGlobalCoarsening<dim, VectorType>::interpolate_to_mg(
-  MGLevelObject<VectorType> &dst,
-  const InVector &           src) const
+MGTransferMF<dim, Number>::interpolate_to_mg(MGLevelObject<VectorType> &dst,
+                                             const InVector &src) const
 {
   const unsigned int min_level = transfer.min_level();
   const unsigned int max_level = transfer.max_level();
@@ -1427,62 +1430,71 @@ MGTransferGlobalCoarsening<dim, VectorType>::interpolate_to_mg(
   AssertDimension(max_level, dst.max_level());
 
   for (unsigned int level = min_level; level <= max_level; ++level)
-    initialize_dof_vector(level, dst[level]);
-
-  dst[transfer.max_level()].copy_locally_owned_data_from(src);
-
-  for (unsigned int l = max_level; l > min_level; --l)
-    this->transfer[l]->interpolate(dst[l - 1], dst[l]);
-}
+    {
+      const bool zero_out_values = false;
+      this->initialize_dof_vector(level, dst[level], src, !zero_out_values);
+    }
 
+  if (this->perform_plain_copy)
+    {
+      dst[max_level].copy_locally_owned_data_from(src);
 
+      for (unsigned int l = max_level; l > min_level; --l)
+        this->transfer[l]->interpolate(dst[l - 1], dst[l]);
+    }
+  else if (this->perform_renumbered_plain_copy)
+    {
+      auto &dst_level = dst[max_level];
 
-template <int dim, typename VectorType>
-template <class InVector>
-void
-MGTransferGlobalCoarsening<dim, VectorType>::interpolate_to_mg(
-  const DoFHandler<dim> &    dof_handler,
-  MGLevelObject<VectorType> &dst,
-  const InVector &           src) const
-{
-  (void)dof_handler;
+      for (unsigned int i = 0; i < this->solution_copy_indices.back().n_cols();
+           ++i)
+        dst_level.local_element(this->solution_copy_indices.back()(1, i)) =
+          src.local_element(i);
 
-  this->interpolate_to_mg(dst, src);
-}
+      for (unsigned int l = max_level; l > min_level; --l)
+        this->transfer[l]->interpolate(dst[l - 1], dst[l]);
+    }
+  else
+    {
+      this->solution_ghosted_global_vector = src;
+      this->solution_ghosted_global_vector.update_ghost_values();
 
+      for (unsigned int l = max_level + 1; l != min_level;)
+        {
+          --l;
 
+          auto &dst_level = dst[l];
 
-template <int dim, typename VectorType>
-std::size_t
-MGTransferGlobalCoarsening<dim, VectorType>::memory_consumption() const
-{
-  std::size_t size = 0;
+          const auto copy_unknowns = [&](const auto &indices) {
+            for (unsigned int i = 0; i < indices.n_cols(); ++i)
+              dst_level.local_element(indices(1, i)) =
+                this->solution_ghosted_global_vector.local_element(
+                  indices(0, i));
+          };
 
-  const unsigned int min_level = transfer.min_level();
-  const unsigned int max_level = transfer.max_level();
+          copy_unknowns(this->solution_copy_indices[l]);
+          copy_unknowns(this->solution_copy_indices_level_mine[l]);
 
-  for (unsigned int l = min_level + 1; l <= max_level; ++l)
-    size += this->transfer[l]->memory_consumption();
+          dst_level.compress(VectorOperation::insert);
 
-  return size;
+          if (l != min_level)
+            this->transfer[l]->interpolate(dst[l - 1], dst[l]);
+        }
+    }
 }
 
 
 
-template <int dim, typename VectorType>
-inline unsigned int
-MGTransferGlobalCoarsening<dim, VectorType>::min_level() const
+template <int dim, typename Number>
+template <class InVector>
+void
+MGTransferMF<dim, Number>::interpolate_to_mg(const DoFHandler<dim> &dof_handler,
+                                             MGLevelObject<VectorType> &dst,
+                                             const InVector &src) const
 {
-  return transfer.min_level();
-}
-
-
+  (void)dof_handler;
 
-template <int dim, typename VectorType>
-inline unsigned int
-MGTransferGlobalCoarsening<dim, VectorType>::max_level() const
-{
-  return transfer.max_level();
+  this->interpolate_to_mg(dst, src);
 }
 
 #endif
index 4b67862f64d16293111b545cabde5aadad1851ac..40c28dc18e716b303058778c5770dd7c881680f2 100644 (file)
@@ -1229,17 +1229,17 @@ namespace internal
                (mg_level_coarse + 1 == mg_level_fine),
              ExcNotImplemented());
 
-      if (mg_level_fine != numbers::invalid_unsigned_int)
-        AssertIndexRange(mg_level_fine,
-                         MGTools::max_level_for_coarse_mesh(
-                           dof_handler_fine.get_triangulation()) +
-                           1);
-
-      if (mg_level_coarse != numbers::invalid_unsigned_int)
-        AssertIndexRange(mg_level_coarse,
-                         MGTools::max_level_for_coarse_mesh(
-                           dof_handler_coarse.get_triangulation()) +
-                           1);
+      // if (mg_level_fine != numbers::invalid_unsigned_int)
+      //   AssertIndexRange(mg_level_fine,
+      //                    MGTools::max_level_for_coarse_mesh(
+      //                      dof_handler_fine.get_triangulation()) +
+      //                      1);
+      //
+      // if (mg_level_coarse != numbers::invalid_unsigned_int)
+      //   AssertIndexRange(mg_level_coarse,
+      //                    MGTools::max_level_for_coarse_mesh(
+      //                      dof_handler_coarse.get_triangulation()) +
+      //                      1);
 
       const GlobalCoarseningFineDoFHandlerView<dim> view(dof_handler_fine,
                                                          dof_handler_coarse,
@@ -3440,27 +3440,345 @@ MGTwoLevelTransferBase<LinearAlgebra::distributed::Vector<Number>>::
 
 
 
-template <int dim, typename VectorType>
-MGTransferBlockGlobalCoarsening<dim, VectorType>::
-  MGTransferBlockGlobalCoarsening(
-    const MGTransferGlobalCoarsening<dim, VectorType> &transfer_operator)
-  : MGTransferBlockMatrixFreeBase<dim,
-                                  typename VectorType::value_type,
-                                  MGTransferGlobalCoarsening<dim, VectorType>>(
-      true)
-  , transfer_operator(transfer_operator)
-{}
+template <int dim, typename Number>
+MGTransferMF<dim, Number>::MGTransferMF(
+  const MGConstrainedDoFs &mg_constrained_dofs)
+{
+  this->initialize_constraints(mg_constrained_dofs);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::initialize_constraints(
+  const MGConstrainedDoFs &mg_constrained_dofs)
+{
+  this->mg_constrained_dofs = &mg_constrained_dofs;
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::intitialize_internal_transfer(
+  const DoFHandler<dim> &                      dof_handler,
+  const SmartPointer<const MGConstrainedDoFs> &mg_constrained_dofs)
+{
+  const unsigned int min_level = 0;
+  const unsigned int max_level =
+    dof_handler.get_triangulation().n_global_levels() - 1;
+
+  MGLevelObject<AffineConstraints<typename VectorType::value_type>> constraints(
+    min_level, max_level);
+
+  if (mg_constrained_dofs)
+    for (unsigned int l = min_level; l <= max_level; ++l)
+      mg_constrained_dofs->merge_constraints(
+        constraints[l],
+        l,
+        /*add_boundary_indices*/ true,
+        /*add_refinement_edge_indices*/ false,
+        /*add_level_constraints*/ true,
+        /*add_user_constraints*/ true);
+
+  this->internal_transfer.resize(min_level, max_level);
+
+  for (unsigned int l = min_level; l < max_level; ++l)
+    internal_transfer[l + 1].reinit_geometric_transfer(
+      dof_handler, dof_handler, constraints[l + 1], constraints[l], l + 1, l);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::build(
+  const std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
+    &external_partitioners)
+{
+  this->external_partitioners = external_partitioners;
+
+  if (this->external_partitioners.size() > 0)
+    {
+      const unsigned int min_level = transfer.min_level();
+      const unsigned int max_level = transfer.max_level();
+
+      AssertDimension(this->external_partitioners.size(), transfer.n_levels());
+
+      for (unsigned int l = min_level + 1; l <= max_level; ++l)
+        transfer[l]->enable_inplace_operations_if_possible(
+          this->external_partitioners[l - 1 - min_level],
+          this->external_partitioners[l - min_level]);
+    }
+  else
+    {
+      const unsigned int min_level = transfer.min_level();
+      const unsigned int max_level = transfer.max_level();
+
+      for (unsigned int l = min_level + 1; l <= max_level; ++l)
+        {
+          if (l == min_level + 1)
+            this->external_partitioners.push_back(
+              transfer[l]->partitioner_coarse);
+
+          this->external_partitioners.push_back(transfer[l]->partitioner_fine);
+        }
+    }
+
+  this->perform_plain_copy            = true;
+  this->perform_renumbered_plain_copy = false;
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::build(
+  const std::function<void(const unsigned int, VectorType &)>
+    &initialize_dof_vector)
+{
+  if (initialize_dof_vector)
+    {
+      const unsigned int min_level = transfer.min_level();
+      const unsigned int max_level = transfer.max_level();
+      const unsigned int n_levels  = transfer.n_levels();
+
+      std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
+        external_partitioners(n_levels);
+
+      for (unsigned int l = min_level; l <= max_level; ++l)
+        {
+          LinearAlgebra::distributed::Vector<typename VectorType::value_type>
+            vector;
+          initialize_dof_vector(l, vector);
+          external_partitioners[l - min_level] = vector.get_partitioner();
+        }
+
+      this->build(external_partitioners);
+    }
+  else
+    {
+      this->build();
+    }
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::build(
+  const DoFHandler<dim> &dof_handler,
+  const std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>>
+    &external_partitioners)
+{
+  this->intitialize_internal_transfer(dof_handler, this->mg_constrained_dofs);
+  this->intitialize_transfer_references(internal_transfer);
+  this->build(external_partitioners);
+  this->fill_and_communicate_copy_indices(dof_handler);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::build(
+  const DoFHandler<dim> &dof_handler,
+  const std::function<void(const unsigned int, VectorType &)>
+    &initialize_dof_vector)
+{
+  this->intitialize_internal_transfer(dof_handler, this->mg_constrained_dofs);
+  this->intitialize_transfer_references(internal_transfer);
+  this->build(initialize_dof_vector);
+  this->fill_and_communicate_copy_indices(dof_handler);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::prolongate(const unsigned int to_level,
+                                      VectorType &       dst,
+                                      const VectorType & src) const
+{
+  dst = 0;
+  prolongate_and_add(to_level, dst, src);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::prolongate_and_add(const unsigned int to_level,
+                                              VectorType &       dst,
+                                              const VectorType & src) const
+{
+  this->transfer[to_level]->prolongate_and_add(dst, src);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferMF<dim, Number>::restrict_and_add(const unsigned int from_level,
+                                            VectorType &       dst,
+                                            const VectorType & src) const
+{
+  this->transfer[from_level]->restrict_and_add(dst, src);
+}
+
+
+
+template <int dim, typename Number>
+std::size_t
+MGTransferMF<dim, Number>::memory_consumption() const
+{
+  std::size_t size = 0;
+
+  const unsigned int min_level = transfer.min_level();
+  const unsigned int max_level = transfer.max_level();
+
+  for (unsigned int l = min_level + 1; l <= max_level; ++l)
+    size += this->transfer[l]->memory_consumption();
+
+  return size;
+}
+
+
+
+template <int dim, typename Number>
+inline unsigned int
+MGTransferMF<dim, Number>::min_level() const
+{
+  return transfer.min_level();
+}
+
+
+
+template <int dim, typename Number>
+inline unsigned int
+MGTransferMF<dim, Number>::max_level() const
+{
+  return transfer.max_level();
+}
+
+
+template <int dim, typename Number>
+inline void
+MGTransferMF<dim, Number>::clear()
+{
+  MGLevelGlobalTransfer<VectorType>::clear();
+
+  internal_transfer.clear();
+  transfer.clear();
+  external_partitioners.clear();
+}
+
+
+
+template <int dim, typename Number>
+MGTransferBlockMF<dim, Number>::MGTransferBlockMF(
+  const MGTransferMF<dim, Number> &transfer_operator)
+  : MGTransferBlockMatrixFreeBase<dim, Number, MGTransferMF<dim, Number>>(true)
+{
+  this->transfer_operators = {&transfer_operator};
+}
+
+
+
+template <int dim, typename Number>
+MGTransferBlockMF<dim, Number>::MGTransferBlockMF(
+  const MGConstrainedDoFs &mg_constrained_dofs)
+  : MGTransferBlockMatrixFreeBase<dim, Number, MGTransferMF<dim, Number>>(true)
+{
+  initialize_constraints(mg_constrained_dofs);
+}
+
+
+
+template <int dim, typename Number>
+MGTransferBlockMF<dim, Number>::MGTransferBlockMF(
+  const std::vector<MGConstrainedDoFs> &mg_constrained_dofs)
+  : MGTransferBlockMatrixFreeBase<dim, Number, MGTransferMF<dim, Number>>(false)
+{
+  initialize_constraints(mg_constrained_dofs);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferBlockMF<dim, Number>::initialize_constraints(
+  const MGConstrainedDoFs &mg_constrained_dofs)
+{
+  this->transfer_operators_internal.clear();
+  this->transfer_operators.clear();
+
+  Assert(this->same_for_all,
+         ExcMessage("This object was initialized with support for usage with "
+                    "one DoFHandler for each block, but this method assumes "
+                    "that the same DoFHandler is used for all the blocks!"));
+
+  this->transfer_operators_internal.emplace_back(mg_constrained_dofs);
+  this->transfer_operators = {&transfer_operators_internal.back()};
+}
 
 
 
-template <int dim, typename VectorType>
-const MGTransferGlobalCoarsening<dim, VectorType> &
-MGTransferBlockGlobalCoarsening<dim, VectorType>::get_matrix_free_transfer(
+template <int dim, typename Number>
+void
+MGTransferBlockMF<dim, Number>::initialize_constraints(
+  const std::vector<MGConstrainedDoFs> &mg_constrained_dofs)
+{
+  this->transfer_operators_internal.clear();
+  this->transfer_operators.clear();
+
+  Assert(!this->same_for_all,
+         ExcMessage("This object was initialized with support for using "
+                    "the same DoFHandler for all the blocks, but this "
+                    "method assumes that there is a separate DoFHandler "
+                    "for each block!"));
+
+  for (const auto &dofs : mg_constrained_dofs)
+    this->transfer_operators_internal.emplace_back(dofs);
+
+  for (const auto &transfer : this->transfer_operators_internal)
+    this->transfer_operators.emplace_back(&transfer);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferBlockMF<dim, Number>::build(const DoFHandler<dim> &dof_handler)
+{
+  AssertDimension(transfer_operators.size(), 1);
+  this->transfer_operators_internal[0].build(dof_handler);
+}
+
+
+
+template <int dim, typename Number>
+void
+MGTransferBlockMF<dim, Number>::build(
+  const std::vector<const DoFHandler<dim> *> &dof_handler)
+{
+  AssertDimension(transfer_operators.size(), dof_handler.size());
+  AssertDimension(transfer_operators_internal.size(), dof_handler.size());
+
+  for (unsigned int i = 0; i < dof_handler.size(); ++i)
+    this->transfer_operators_internal[i].build(*dof_handler[i]);
+}
+
+
+
+template <int dim, typename Number>
+const MGTransferMF<dim, Number> &
+MGTransferBlockMF<dim, Number>::get_matrix_free_transfer(
   const unsigned int b) const
 {
-  (void)b;
-  AssertDimension(b, 0);
-  return transfer_operator;
+  AssertIndexRange(b, transfer_operators.size());
+  return *transfer_operators[b];
 }
 
 namespace internal
index 5abd0f0effc9f609c7710240319fd744e4a542d4..61fd9ba060c66fff091da87f76e7ce0149ee65af 100644 (file)
@@ -160,11 +160,8 @@ namespace
   template <int dim, int spacedim, typename Number>
   void
   fill_internal(
-    const DoFHandler<dim, spacedim> &mg_dof,
-    SmartPointer<
-      const MGConstrainedDoFs,
-      MGLevelGlobalTransfer<LinearAlgebra::distributed::Vector<Number>>>
-                                                mg_constrained_dofs,
+    const DoFHandler<dim, spacedim> &           mg_dof,
+    SmartPointer<const MGConstrainedDoFs>       mg_constrained_dofs,
     const MPI_Comm                              mpi_communicator,
     const bool                                  transfer_solution_vectors,
     std::vector<Table<2, unsigned int>> &       copy_indices,
index 49edd3085da151639d0dbdf8b4f76d1a76743aa3..62a96003494f826dfa8a46ede176881a23bbe8c5 100644 (file)
@@ -30,11 +30,9 @@ for (deal_II_dimension : DIMENSIONS; S1 : REAL_SCALARS)
     template class MGTransferBlockMatrixFreeBase<
       deal_II_dimension,
       S1,
-      MGTransferGlobalCoarsening<deal_II_dimension,
-                                 LinearAlgebra::distributed::Vector<S1>>>;
-    template class MGTransferBlockGlobalCoarsening<
-      deal_II_dimension,
-      LinearAlgebra::distributed::Vector<S1>>;
+      MGTransferMF<deal_II_dimension, S1>>;
+    template class MGTransferMF<deal_II_dimension, S1>;
+    template class MGTransferBlockMF<deal_II_dimension, S1>;
   }
 
 for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS)
diff --git a/tests/multigrid-global-coarsening/interpolate_to_mg.cc b/tests/multigrid-global-coarsening/interpolate_to_mg.cc
new file mode 100644 (file)
index 0000000..2963931
--- /dev/null
@@ -0,0 +1,275 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// test MGTransferMatrixFree<dim,Number>::interpolate_to_mg()
+// for a scalar field
+
+#include <deal.II/base/function.h>
+#include <deal.II/base/multithread_info.h>
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/thread_management.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/mapping_q1.h>
+#include <deal.II/fe/mapping_q_eulerian.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/full_matrix.h>
+#include <deal.II/lac/identity_matrix.h>
+#include <deal.II/lac/petsc_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/sparse_matrix.h>
+#include <deal.II/lac/vector.h>
+#include <deal.II/lac/vector_memory.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include <iostream>
+#include <vector>
+
+#include "../tests.h"
+
+
+
+template <int dim>
+class SimpleField : public Function<dim>
+{
+public:
+  SimpleField()
+    : Function<dim>(1)
+  {}
+
+  double
+  value(const Point<dim> &p, const unsigned int component = 0) const
+  {
+    (void)component;
+    return p[0] * 2. + p[1] - 10.;
+  }
+};
+
+
+template <int dim,
+          int fe_degree            = 2,
+          int n_q_points           = fe_degree + 1,
+          typename NumberType      = double,
+          typename LevelNumberType = NumberType>
+void
+test(const unsigned int n_glob_ref = 2, const unsigned int n_ref = 0)
+{
+  SimpleField<dim> function;
+
+  deallog << "dim=" << dim << std::endl;
+  MPI_Comm     mpi_communicator(MPI_COMM_WORLD);
+  unsigned int myid    = Utilities::MPI::this_mpi_process(mpi_communicator);
+  unsigned int numproc = Utilities::MPI::n_mpi_processes(mpi_communicator);
+
+  deallog << "numproc=" << numproc << std::endl;
+
+  parallel::distributed::Triangulation<dim> triangulation(
+    mpi_communicator,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::subdivided_hyper_cube(triangulation, 5, -1, 1);
+  // now do some refinement
+  triangulation.refine_global(n_glob_ref);
+  for (unsigned int ref = 0; ref < n_ref; ++ref)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             triangulation.begin_active();
+           cell != triangulation.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      triangulation.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim>       fe(fe_degree);
+  DoFHandler<dim> dof_handler(triangulation);
+
+  dof_handler.distribute_dofs(fe);
+  dof_handler.distribute_mg_dofs();
+
+  IndexSet locally_owned_dofs, locally_relevant_dofs;
+  locally_owned_dofs = dof_handler.locally_owned_dofs();
+  DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
+
+  // constraints:
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+  constraints.close();
+
+
+  // interpolate:
+  LinearAlgebra::distributed::Vector<LevelNumberType> fine_projection;
+  fine_projection.reinit(locally_owned_dofs,
+                         locally_relevant_dofs,
+                         mpi_communicator);
+  VectorTools::project(dof_handler,
+                       constraints,
+                       QGauss<dim>(n_q_points + 2),
+                       function,
+                       fine_projection);
+  fine_projection.update_ghost_values();
+
+  // output for debug purposes:
+  if (false)
+    {
+      DataOut<dim> data_out;
+      data_out.attach_dof_handler(dof_handler);
+      data_out.add_data_vector(fine_projection, "projection");
+
+      Vector<float> subdomain(triangulation.n_active_cells());
+      for (unsigned int i = 0; i < subdomain.size(); ++i)
+        subdomain(i) = triangulation.locally_owned_subdomain();
+      data_out.add_data_vector(subdomain, "subdomain");
+      data_out.build_patches();
+      const std::string filename =
+        "output_" + Utilities::int_to_string(myid) + ".vtu";
+      std::ofstream output(filename);
+      data_out.write_vtu(output);
+
+      const std::string mg_mesh = "mg_mesh";
+      GridOut           grid_out;
+      grid_out.write_mesh_per_processor_as_vtu(triangulation,
+                                               mg_mesh,
+                                               true,
+                                               true);
+    }
+
+  // MG hanging node constraints
+  // we do not add extra zero Dirichlet BC here
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof_handler);
+
+  // MG transfer:
+  MGTransferMF<dim, LevelNumberType> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof_handler);
+
+  // now the core of the test:
+  const unsigned int max_level =
+    dof_handler.get_triangulation().n_global_levels() - 1;
+  const unsigned int min_level = 0;
+  MGLevelObject<LinearAlgebra::distributed::Vector<LevelNumberType>>
+    level_projection(min_level, max_level);
+  for (unsigned int level = min_level; level <= max_level; ++level)
+    {
+      IndexSet set;
+      DoFTools::extract_locally_relevant_level_dofs(dof_handler, level, set);
+      level_projection[level].reinit(dof_handler.locally_owned_mg_dofs(level),
+                                     set,
+                                     mpi_communicator);
+    }
+  mg_transfer.interpolate_to_mg(dof_handler, level_projection, fine_projection);
+
+  // now go through all GMG levels and make sure FE field can represent
+  // analytic function exactly:
+  QGauss<dim>                  quadrature(n_q_points);
+  std::vector<LevelNumberType> q_values(quadrature.size());
+
+  FEValues<dim> fe_values(fe,
+                          quadrature,
+                          update_values | update_quadrature_points);
+  for (unsigned int level = max_level + 1; level != min_level;)
+    {
+      --level;
+
+      level_projection[level].update_ghost_values();
+
+      std::vector<types::global_dof_index>    dof_indices(fe.dofs_per_cell);
+      typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level);
+      typename DoFHandler<dim>::cell_iterator endc = dof_handler.end(level);
+      for (; cell != endc; ++cell)
+        if (cell->is_locally_owned_on_level())
+          {
+            fe_values.reinit(cell);
+            cell->get_mg_dof_indices(dof_indices);
+            fe_values.get_function_values(level_projection[level],
+                                          dof_indices,
+                                          q_values);
+
+            const std::vector<Point<dim>> &q_points =
+              fe_values.get_quadrature_points();
+
+            for (unsigned int q = 0; q < q_points.size(); ++q)
+              {
+                const double diff = q_values[q] - function.value(q_points[q]);
+                if (std::abs(diff) > 1e-10)
+                  {
+                    std::cout << "dofs: ";
+                    for (const auto i : dof_indices)
+                      std::cout << i << ' ';
+                    std::cout << std::endl << "values: ";
+                    std::vector<LevelNumberType> local_values(
+                      dof_indices.size());
+                    level_projection[level].extract_subvector_to(dof_indices,
+                                                                 local_values);
+                    for (const auto v : local_values)
+                      std::cout << v << ' ';
+                    std::cout << std::endl
+                              << "val(q)=" << q_values[q] << std::endl;
+                    std::cout << "MGTransfer indices:" << std::endl;
+                    mg_transfer.print_indices(std::cout);
+                    AssertThrow(false,
+                                ExcMessage("Level " + std::to_string(level) +
+                                           " Diff " + std::to_string(diff) +
+                                           " center_x " +
+                                           std::to_string(cell->center()[0]) +
+                                           " center_y " +
+                                           std::to_string(cell->center()[1])));
+                  }
+              }
+          }
+    }
+
+  deallog << "Ok" << std::endl;
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
+  MPILogInitAll                    log;
+
+  test<2>();
+  test<2, 1>(0, 1);
+}
diff --git a/tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=1.output b/tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..dad0ed2
--- /dev/null
@@ -0,0 +1,7 @@
+
+DEAL:0::dim=2
+DEAL:0::numproc=1
+DEAL:0::Ok
+DEAL:0::dim=2
+DEAL:0::numproc=1
+DEAL:0::Ok
diff --git a/tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/interpolate_to_mg.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..a4a6802
--- /dev/null
@@ -0,0 +1,23 @@
+
+DEAL:0::dim=2
+DEAL:0::numproc=3
+DEAL:0::Ok
+DEAL:0::dim=2
+DEAL:0::numproc=3
+DEAL:0::Ok
+
+DEAL:1::dim=2
+DEAL:1::numproc=3
+DEAL:1::Ok
+DEAL:1::dim=2
+DEAL:1::numproc=3
+DEAL:1::Ok
+
+
+DEAL:2::dim=2
+DEAL:2::numproc=3
+DEAL:2::Ok
+DEAL:2::dim=2
+DEAL:2::numproc=3
+DEAL:2::Ok
+
diff --git a/tests/multigrid-global-coarsening/interpolate_to_mg_01.cc b/tests/multigrid-global-coarsening/interpolate_to_mg_01.cc
new file mode 100644 (file)
index 0000000..a58f985
--- /dev/null
@@ -0,0 +1,134 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2021 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// test function MGTransferMatrixFree::interpolate_to_mg() for periodic
+// boundaries
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/mapping_q1.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+template <int dim>
+class RightHandSideFunction : public Function<dim>
+{
+public:
+  RightHandSideFunction(const unsigned int n_components)
+    : Function<dim>(n_components)
+  {}
+
+  virtual double
+  value(const Point<dim> &p, const unsigned int component = 0) const
+  {
+    return p[component % dim] * p[component % dim];
+  }
+};
+
+template <int dim>
+void
+test()
+{
+  const unsigned int fe_degree = 1;
+
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+
+  GridGenerator::hyper_cube(tria, -1., 1., true);
+
+  std::vector<GridTools::PeriodicFacePair<TriaIterator<CellAccessor<dim, dim>>>>
+    tria_matched_pairs;
+  GridTools::collect_periodic_faces(tria, 0, 1, 0, tria_matched_pairs);
+  tria.add_periodicity(tria_matched_pairs);
+  tria.refine_global(2);
+
+  const FE_Q<dim> fe(fe_degree);
+  DoFHandler<dim> dof_handler(tria);
+  dof_handler.distribute_dofs(fe);
+  dof_handler.distribute_mg_dofs();
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
+
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+
+  std::vector<
+    GridTools::PeriodicFacePair<typename DoFHandler<dim>::cell_iterator>>
+    dof_matched_pairs;
+  GridTools::collect_periodic_faces(dof_handler, 0, 1, 0, dof_matched_pairs);
+  DoFTools::make_periodicity_constraints<dim, dim>(dof_matched_pairs,
+                                                   constraints);
+  constraints.close();
+
+  LinearAlgebra::distributed::Vector<double> qsol(
+    dof_handler.locally_owned_dofs(), locally_relevant_dofs, MPI_COMM_WORLD);
+
+  VectorTools::interpolate(MappingQ1<dim>(),
+                           dof_handler,
+                           RightHandSideFunction<dim>(1),
+                           qsol);
+
+  MGLevelObject<LinearAlgebra::distributed::Vector<double>> mg_qsol;
+  MGConstrainedDoFs                                         mg_constrained_dofs;
+  MGTransferMF<dim, double>                                 mg_transfer;
+
+  unsigned int n_tria_levels = tria.n_global_levels();
+  mg_qsol.resize(0, n_tria_levels - 1);
+
+  mg_constrained_dofs.initialize(dof_handler);
+  mg_transfer.initialize_constraints(mg_constrained_dofs);
+  mg_transfer.build(dof_handler);
+
+  mg_transfer.interpolate_to_mg(dof_handler, mg_qsol, qsol);
+
+  for (unsigned int i = mg_qsol.min_level(); i <= mg_qsol.max_level(); ++i)
+    deallog << mg_qsol[i].l2_norm() << std::endl;
+
+  deallog << "OK" << std::endl;
+}
+
+
+
+int
+main(int argc, char *argv[])
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
+  MPILogInitAll                    all;
+
+  test<2>();
+}
diff --git a/tests/multigrid-global-coarsening/interpolate_to_mg_01.with_p4est=true.mpirun=2.output b/tests/multigrid-global-coarsening/interpolate_to_mg_01.with_p4est=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..5bc629f
--- /dev/null
@@ -0,0 +1,11 @@
+
+DEAL:0::2.00000
+DEAL:0::2.44949
+DEAL:0::3.25960
+DEAL:0::OK
+
+DEAL:1::2.00000
+DEAL:1::2.44949
+DEAL:1::3.25960
+DEAL:1::OK
+
diff --git a/tests/multigrid-global-coarsening/mg_data_out_04.cc b/tests/multigrid-global-coarsening/mg_data_out_04.cc
new file mode 100644 (file)
index 0000000..7504161
--- /dev/null
@@ -0,0 +1,123 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2006 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+// Test DataOut::add_mg_data_vector in parallel
+
+#include <deal.II/base/function_lib.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim>
+void
+do_test()
+{
+  parallel::distributed::Triangulation<dim> triangulation(
+    MPI_COMM_WORLD,
+    dealii::Triangulation<dim>::none,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+
+  GridGenerator::hyper_cube(triangulation);
+  triangulation.refine_global(1);
+  triangulation.begin_active()->set_refine_flag();
+  triangulation.execute_coarsening_and_refinement();
+
+  FE_Q<dim>       fe(1);
+  DoFHandler<dim> dof_handler(triangulation);
+  dof_handler.distribute_dofs(fe);
+  dof_handler.distribute_mg_dofs();
+
+  // Make FE vector
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
+
+  using VectorType = LinearAlgebra::distributed::Vector<double>;
+  VectorType global_dof_vector;
+  global_dof_vector.reinit(dof_handler.locally_owned_dofs(),
+                           locally_relevant_dofs,
+                           MPI_COMM_WORLD);
+
+  VectorTools::interpolate(dof_handler,
+                           Functions::SquareFunction<dim>(),
+                           global_dof_vector);
+  global_dof_vector.update_ghost_values();
+
+  {
+    DataOut<dim> data_out;
+    data_out.attach_dof_handler(dof_handler);
+    data_out.add_data_vector(dof_handler,
+                             global_dof_vector,
+                             std::vector<std::string>(1, "data"));
+    data_out.build_patches(0);
+    data_out.write_gnuplot(deallog.get_file_stream());
+    data_out.write_vtu_in_parallel("base.vtu", MPI_COMM_WORLD);
+  }
+
+  {
+    MGLevelObject<VectorType>                          dof_vector(0,
+                                         triangulation.n_global_levels() - 1);
+    MGTransferMF<dim, typename VectorType::value_type> transfer;
+
+    transfer.build(dof_handler);
+    transfer.interpolate_to_mg(dof_handler, dof_vector, global_dof_vector);
+
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      {
+        deallog << "* level " << level << std::endl;
+        DataOut<dim> data_out;
+        data_out.set_cell_selection(
+          [level](const typename Triangulation<dim>::cell_iterator &cell) {
+            return (cell->level() == static_cast<int>(level) &&
+                    cell->is_locally_owned_on_level());
+          });
+        data_out.attach_triangulation(triangulation);
+        dof_vector[level].update_ghost_values();
+        data_out.add_mg_data_vector(dof_handler, dof_vector, "data");
+        data_out.build_patches(0);
+        data_out.write_gnuplot(deallog.get_file_stream());
+        data_out.write_vtu_in_parallel(std::string("level") +
+                                         Utilities::to_string(level) + ".vtu",
+                                       MPI_COMM_WORLD);
+      }
+  }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  MPILogInitAll                    log;
+
+  do_test<2>();
+  //  do_test<3>();
+  return 0;
+}
diff --git a/tests/multigrid-global-coarsening/mg_data_out_04.with_p4est=true.mpirun=2.output b/tests/multigrid-global-coarsening/mg_data_out_04.with_p4est=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..568ac41
--- /dev/null
@@ -0,0 +1,163 @@
+
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.00000 0.00000 0.00000 
+0.250000 0.00000 0.0625000 
+
+0.00000 0.250000 0.0625000 
+0.250000 0.250000 0.125000 
+
+
+0.250000 0.00000 0.0625000 
+0.500000 0.00000 0.250000 
+
+0.250000 0.250000 0.125000 
+0.500000 0.250000 0.312500 
+
+
+0.00000 0.250000 0.0625000 
+0.250000 0.250000 0.125000 
+
+0.00000 0.500000 0.250000 
+0.250000 0.500000 0.312500 
+
+
+0.250000 0.250000 0.125000 
+0.500000 0.250000 0.312500 
+
+0.250000 0.500000 0.312500 
+0.500000 0.500000 0.500000 
+
+
+DEAL:0::* level 0
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.00000 0.00000 0.00000 
+1.00000 0.00000 1.00000 
+
+0.00000 1.00000 1.00000 
+1.00000 1.00000 2.00000 
+
+
+DEAL:0::* level 1
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.00000 0.00000 0.00000 
+0.500000 0.00000 0.250000 
+
+0.00000 0.500000 0.250000 
+0.500000 0.500000 0.500000 
+
+
+DEAL:0::* level 2
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.00000 0.00000 0.00000 
+0.250000 0.00000 0.0625000 
+
+0.00000 0.250000 0.0625000 
+0.250000 0.250000 0.125000 
+
+
+0.250000 0.00000 0.0625000 
+0.500000 0.00000 0.250000 
+
+0.250000 0.250000 0.125000 
+0.500000 0.250000 0.312500 
+
+
+0.00000 0.250000 0.0625000 
+0.250000 0.250000 0.125000 
+
+0.00000 0.500000 0.250000 
+0.250000 0.500000 0.312500 
+
+
+0.250000 0.250000 0.125000 
+0.500000 0.250000 0.312500 
+
+0.250000 0.500000 0.312500 
+0.500000 0.500000 0.500000 
+
+
+
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.500000 0.00000 0.250000 
+1.00000 0.00000 1.00000 
+
+0.500000 0.500000 0.500000 
+1.00000 0.500000 1.25000 
+
+
+0.00000 0.500000 0.250000 
+0.500000 0.500000 0.500000 
+
+0.00000 1.00000 1.00000 
+0.500000 1.00000 1.25000 
+
+
+0.500000 0.500000 0.500000 
+1.00000 0.500000 1.25000 
+
+0.500000 1.00000 1.25000 
+1.00000 1.00000 2.00000 
+
+
+DEAL:1::* level 0
+DEAL:1::* level 1
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data> 
+0.500000 0.00000 0.250000 
+1.00000 0.00000 1.00000 
+
+0.500000 0.500000 0.500000 
+1.00000 0.500000 1.25000 
+
+
+0.00000 0.500000 0.250000 
+0.500000 0.500000 0.500000 
+
+0.00000 1.00000 1.00000 
+0.500000 1.00000 1.25000 
+
+
+0.500000 0.500000 0.500000 
+1.00000 0.500000 1.25000 
+
+0.500000 1.00000 1.25000 
+1.00000 1.00000 2.00000 
+
+
+DEAL:1::* level 2
+
diff --git a/tests/multigrid-global-coarsening/mg_data_out_05.cc b/tests/multigrid-global-coarsening/mg_data_out_05.cc
new file mode 100644 (file)
index 0000000..5848f0e
--- /dev/null
@@ -0,0 +1,151 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2006 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+// Test DataOut::add_mg_data_vector in parallel for a vector valued dof function
+
+#include <deal.II/base/function_lib.h>
+#include <deal.II/base/function_parser.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim>
+void
+do_test()
+{
+  parallel::distributed::Triangulation<dim> triangulation(
+    MPI_COMM_WORLD,
+    dealii::Triangulation<dim>::none,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+
+  GridGenerator::hyper_cube(triangulation);
+  triangulation.refine_global(1);
+  triangulation.begin_active()->set_refine_flag();
+  triangulation.execute_coarsening_and_refinement();
+
+  FESystem<dim> fe(FE_DGQ<dim>(1), dim + 1);
+
+  DoFHandler<dim> dof_handler(triangulation);
+  dof_handler.distribute_dofs(fe);
+  dof_handler.distribute_mg_dofs();
+
+  // Make FE vector
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
+
+  using VectorType = LinearAlgebra::distributed::Vector<double>;
+  VectorType global_dof_vector;
+  global_dof_vector.reinit(dof_handler.locally_owned_dofs(),
+                           locally_relevant_dofs,
+                           MPI_COMM_WORLD);
+
+  QGauss<dim> quadrature(3);
+
+  FunctionParser<dim> function(dim == 2 ? "y;-x;x*x+y*y" :
+                                          "y;-x;0;x*x+y*y+z*z");
+
+  AffineConstraints<double> constraints;
+  DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+  constraints.close();
+  VectorTools::project(
+    dof_handler, constraints, quadrature, function, global_dof_vector);
+  /*  VectorTools::interpolate(dof_handler,
+                           Functions::SquareFunction<dim>(),
+                           global_dof_vector);
+  */
+
+  global_dof_vector.update_ghost_values();
+
+  std::vector<std::string> names(dim, "vec");
+  names.emplace_back("my_scalar");
+  std::vector<DataComponentInterpretation::DataComponentInterpretation>
+    interpretation(dim,
+                   DataComponentInterpretation::component_is_part_of_vector);
+  interpretation.emplace_back(DataComponentInterpretation::component_is_scalar);
+
+  {
+    DataOut<dim> data_out;
+    data_out.attach_dof_handler(dof_handler);
+    data_out.add_data_vector(dof_handler,
+                             global_dof_vector,
+                             names,
+                             interpretation);
+    data_out.build_patches(0);
+    data_out.write_gnuplot(deallog.get_file_stream());
+    data_out.write_vtu_in_parallel("base.vtu", MPI_COMM_WORLD);
+  }
+
+  {
+    MGLevelObject<VectorType>                          dof_vector(0,
+                                         triangulation.n_global_levels() - 1);
+    MGTransferMF<dim, typename VectorType::value_type> transfer;
+
+    transfer.build(dof_handler);
+    transfer.interpolate_to_mg(dof_handler, dof_vector, global_dof_vector);
+
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      {
+        deallog << "* level " << level << std::endl;
+        DataOut<dim> data_out;
+        data_out.set_cell_selection(
+          [level](const typename Triangulation<dim>::cell_iterator &cell) {
+            return (cell->level() == static_cast<int>(level) &&
+                    cell->is_locally_owned_on_level());
+          });
+        data_out.attach_triangulation(triangulation);
+        dof_vector[level].update_ghost_values();
+        data_out.add_mg_data_vector(dof_handler, dof_vector, "data");
+        data_out.add_mg_data_vector(dof_handler,
+                                    dof_vector,
+                                    names,
+                                    interpretation);
+        data_out.build_patches(0);
+        data_out.write_gnuplot(deallog.get_file_stream());
+        data_out.write_vtu_in_parallel(std::string("level") +
+                                         Utilities::to_string(level) + ".vtu",
+                                       MPI_COMM_WORLD);
+      }
+  }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  MPILogInitAll                    log;
+
+  do_test<2>();
+  //  do_test<3>();
+  return 0;
+}
diff --git a/tests/multigrid-global-coarsening/mg_data_out_05.with_p4est=true.mpirun=2.output b/tests/multigrid-global-coarsening/mg_data_out_05.with_p4est=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..b816a43
--- /dev/null
@@ -0,0 +1,163 @@
+
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <vec> <vec> <my_scalar> 
+0.00000 0.00000 -6.93889e-17 2.77556e-17 -0.0208333 
+0.250000 0.00000 -5.55112e-17 -0.250000 0.0416667 
+
+0.00000 0.250000 0.250000 2.77556e-17 0.0416667 
+0.250000 0.250000 0.250000 -0.250000 0.104167 
+
+
+0.250000 0.00000 -6.93889e-17 -0.250000 0.0416667 
+0.500000 0.00000 -5.55112e-17 -0.500000 0.229167 
+
+0.250000 0.250000 0.250000 -0.250000 0.104167 
+0.500000 0.250000 0.250000 -0.500000 0.291667 
+
+
+0.00000 0.250000 0.250000 2.77556e-17 0.0416667 
+0.250000 0.250000 0.250000 -0.250000 0.104167 
+
+0.00000 0.500000 0.500000 2.77556e-17 0.229167 
+0.250000 0.500000 0.500000 -0.250000 0.291667 
+
+
+0.250000 0.250000 0.250000 -0.250000 0.104167 
+0.500000 0.250000 0.250000 -0.500000 0.291667 
+
+0.250000 0.500000 0.500000 -0.250000 0.291667 
+0.500000 0.500000 0.500000 -0.500000 0.479167 
+
+
+DEAL:0::* level 0
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data_0> <data_1> <data_2> <vec> <vec> <my_scalar> 
+0.00000 0.00000 -2.35922e-16 1.24900e-16 -0.333333 -2.35922e-16 1.24900e-16 -0.333333 
+1.00000 0.00000 5.55112e-17 -1.00000 0.666667 5.55112e-17 -1.00000 0.666667 
+
+0.00000 1.00000 1.00000 1.66533e-16 0.666667 1.00000 1.66533e-16 0.666667 
+1.00000 1.00000 1.00000 -1.00000 1.66667 1.00000 -1.00000 1.66667 
+
+
+DEAL:0::* level 1
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data_0> <data_1> <data_2> <vec> <vec> <my_scalar> 
+0.00000 0.00000 -3.46945e-17 6.93889e-18 -0.0833333 -3.46945e-17 6.93889e-18 -0.0833333 
+0.500000 0.00000 0.00000 -0.500000 0.166667 0.00000 -0.500000 0.166667 
+
+0.00000 0.500000 0.500000 1.11022e-16 0.166667 0.500000 1.11022e-16 0.166667 
+0.500000 0.500000 0.500000 -0.500000 0.416667 0.500000 -0.500000 0.416667 
+
+
+DEAL:0::* level 2
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data_0> <data_1> <data_2> <vec> <vec> <my_scalar> 
+0.00000 0.00000 -6.93889e-17 2.77556e-17 -0.0208333 -6.93889e-17 2.77556e-17 -0.0208333 
+0.250000 0.00000 -5.55112e-17 -0.250000 0.0416667 -5.55112e-17 -0.250000 0.0416667 
+
+0.00000 0.250000 0.250000 2.77556e-17 0.0416667 0.250000 2.77556e-17 0.0416667 
+0.250000 0.250000 0.250000 -0.250000 0.104167 0.250000 -0.250000 0.104167 
+
+
+0.250000 0.00000 -6.93889e-17 -0.250000 0.0416667 -6.93889e-17 -0.250000 0.0416667 
+0.500000 0.00000 -5.55112e-17 -0.500000 0.229167 -5.55112e-17 -0.500000 0.229167 
+
+0.250000 0.250000 0.250000 -0.250000 0.104167 0.250000 -0.250000 0.104167 
+0.500000 0.250000 0.250000 -0.500000 0.291667 0.250000 -0.500000 0.291667 
+
+
+0.00000 0.250000 0.250000 2.77556e-17 0.0416667 0.250000 2.77556e-17 0.0416667 
+0.250000 0.250000 0.250000 -0.250000 0.104167 0.250000 -0.250000 0.104167 
+
+0.00000 0.500000 0.500000 2.77556e-17 0.229167 0.500000 2.77556e-17 0.229167 
+0.250000 0.500000 0.500000 -0.250000 0.291667 0.500000 -0.250000 0.291667 
+
+
+0.250000 0.250000 0.250000 -0.250000 0.104167 0.250000 -0.250000 0.104167 
+0.500000 0.250000 0.250000 -0.500000 0.291667 0.250000 -0.500000 0.291667 
+
+0.250000 0.500000 0.500000 -0.250000 0.291667 0.500000 -0.250000 0.291667 
+0.500000 0.500000 0.500000 -0.500000 0.479167 0.500000 -0.500000 0.479167 
+
+
+
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <vec> <vec> <my_scalar> 
+0.500000 0.00000 -1.38778e-16 -0.500000 0.166667 
+1.00000 0.00000 -1.11022e-16 -1.00000 0.916667 
+
+0.500000 0.500000 0.500000 -0.500000 0.416667 
+1.00000 0.500000 0.500000 -1.00000 1.16667 
+
+
+0.00000 0.500000 0.500000 5.55112e-17 0.166667 
+0.500000 0.500000 0.500000 -0.500000 0.416667 
+
+0.00000 1.00000 1.00000 5.55112e-17 0.916667 
+0.500000 1.00000 1.00000 -0.500000 1.16667 
+
+
+0.500000 0.500000 0.500000 -0.500000 0.416667 
+1.00000 0.500000 0.500000 -1.00000 1.16667 
+
+0.500000 1.00000 1.00000 -0.500000 1.16667 
+1.00000 1.00000 1.00000 -1.00000 1.91667 
+
+
+DEAL:1::* level 0
+DEAL:1::* level 1
+# This file was generated by the deal.II library.
+
+
+#
+# For a description of the GNUPLOT format see the GNUPLOT manual.
+#
+# <x> <y> <data_0> <data_1> <data_2> <vec> <vec> <my_scalar> 
+0.500000 0.00000 -1.38778e-16 -0.500000 0.166667 -1.38778e-16 -0.500000 0.166667 
+1.00000 0.00000 -1.11022e-16 -1.00000 0.916667 -1.11022e-16 -1.00000 0.916667 
+
+0.500000 0.500000 0.500000 -0.500000 0.416667 0.500000 -0.500000 0.416667 
+1.00000 0.500000 0.500000 -1.00000 1.16667 0.500000 -1.00000 1.16667 
+
+
+0.00000 0.500000 0.500000 5.55112e-17 0.166667 0.500000 5.55112e-17 0.166667 
+0.500000 0.500000 0.500000 -0.500000 0.416667 0.500000 -0.500000 0.416667 
+
+0.00000 1.00000 1.00000 5.55112e-17 0.916667 1.00000 5.55112e-17 0.916667 
+0.500000 1.00000 1.00000 -0.500000 1.16667 1.00000 -0.500000 1.16667 
+
+
+0.500000 0.500000 0.500000 -0.500000 0.416667 0.500000 -0.500000 0.416667 
+1.00000 0.500000 0.500000 -1.00000 1.16667 0.500000 -1.00000 1.16667 
+
+0.500000 1.00000 1.00000 -0.500000 1.16667 1.00000 -0.500000 1.16667 
+1.00000 1.00000 1.00000 -1.00000 1.91667 1.00000 -1.00000 1.91667 
+
+
+DEAL:1::* level 2
+
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_periodic.cc b/tests/multigrid-global-coarsening/multigrid_dg_periodic.cc
new file mode 100644 (file)
index 0000000..736aa64
--- /dev/null
@@ -0,0 +1,639 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2018 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// same as multigrid_dg_sip but using periodic boundary conditions
+
+#include <deal.II/base/function.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <int dim, typename number = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &   mapping,
+             const DoFHandler<dim> &dof_handler,
+             const unsigned int     n_q_points_1d,
+             const unsigned int     level = numbers::invalid_unsigned_int)
+  {
+    fe_degree = dof_handler.get_fe().degree;
+
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    addit_data.mapping_update_flags_inner_faces =
+      (update_gradients | update_JxW_values);
+    addit_data.mapping_update_flags_boundary_faces =
+      (update_gradients | update_JxW_values);
+    AffineConstraints<double> constraints;
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    data.loop(&LaplaceOperator::local_apply,
+              &LaplaceOperator::local_apply_face,
+              &LaplaceOperator::local_apply_boundary,
+              this,
+              dst,
+              src);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_face(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval_neighbor(data, false);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval_neighbor.reinit(face);
+
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval_neighbor.read_dof_values(src);
+        fe_eval_neighbor.evaluate(EvaluationFlags::values |
+                                  EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          (std::abs((fe_eval.normal_vector(0) *
+                     fe_eval.inverse_jacobian(0))[dim - 1]) +
+           std::abs((fe_eval.normal_vector(0) *
+                     fe_eval_neighbor.inverse_jacobian(0))[dim - 1])) *
+          (number)(std::max(fe_degree, 1) * (fe_degree + 1.0));
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value =
+              (fe_eval.get_value(q) - fe_eval_neighbor.get_value(q)) * 0.5;
+            VectorizedArray<number> average_valgrad =
+              fe_eval.get_normal_derivative(q) +
+              fe_eval_neighbor.get_normal_derivative(q);
+            average_valgrad =
+              average_value * 2. * sigmaF - average_valgrad * 0.5;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval_neighbor.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+            fe_eval_neighbor.submit_value(-average_valgrad, q);
+          }
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+        fe_eval_neighbor.integrate(EvaluationFlags::values |
+                                   EvaluationFlags::gradients);
+        fe_eval_neighbor.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_boundary(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          std::abs(
+            (fe_eval.normal_vector(0) * fe_eval.inverse_jacobian(0))[dim - 1]) *
+          (number)(std::max(1, fe_degree) * (fe_degree + 1.0)) * 2.;
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value = fe_eval.get_value(q);
+            VectorizedArray<number> average_valgrad =
+              -fe_eval.get_normal_derivative(q);
+            average_valgrad += average_value * sigmaF * 2.0;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+          }
+
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.loop(&LaplaceOperator::local_diagonal_cell,
+              &LaplaceOperator::local_diagonal_face,
+              &LaplaceOperator::local_diagonal_boundary,
+              this,
+              inverse_diagonal_entries,
+              dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number>    phi(data);
+    AlignedVector<VectorizedArray<number>> local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_diagonal_face(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi(data, true);
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi_outer(data, false);
+    AlignedVector<VectorizedArray<number>>  local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        phi.reinit(face);
+        phi_outer.reinit(face);
+
+        VectorizedArray<number> sigmaF =
+          (std::abs((phi.normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]) +
+           std::abs(
+             (phi.normal_vector(0) * phi_outer.inverse_jacobian(0))[dim - 1])) *
+          (number)(std::max(fe_degree, 1) * (fe_degree + 1.0));
+
+        // Compute phi part
+        for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+          phi_outer.begin_dof_values()[j] = VectorizedArray<number>();
+        phi_outer.evaluate(EvaluationFlags::values |
+                           EvaluationFlags::gradients);
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value =
+                  (phi.get_value(q) - phi_outer.get_value(q)) * 0.5;
+                VectorizedArray<number> average_valgrad =
+                  phi.get_normal_derivative(q) +
+                  phi_outer.get_normal_derivative(q);
+                average_valgrad =
+                  average_value * 2. * sigmaF - average_valgrad * 0.5;
+                phi.submit_normal_derivative(-average_value, q);
+                phi.submit_value(average_valgrad, q);
+              }
+            phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+
+        // Compute phi_outer part
+        for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+          phi.begin_dof_values()[j] = VectorizedArray<number>();
+        phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi_outer.begin_dof_values()[j] = VectorizedArray<number>();
+            phi_outer.begin_dof_values()[i] = 1.;
+            phi_outer.evaluate(EvaluationFlags::values |
+                               EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value =
+                  (phi.get_value(q) - phi_outer.get_value(q)) * 0.5;
+                VectorizedArray<number> average_valgrad =
+                  phi.get_normal_derivative(q) +
+                  phi_outer.get_normal_derivative(q);
+                average_valgrad =
+                  average_value * 2. * sigmaF - average_valgrad * 0.5;
+                phi_outer.submit_normal_derivative(-average_value, q);
+                phi_outer.submit_value(-average_valgrad, q);
+              }
+            phi_outer.integrate(EvaluationFlags::values |
+                                EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi_outer.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi_outer.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi_outer.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_diagonal_boundary(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi(data);
+    AlignedVector<VectorizedArray<number>>  local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        phi.reinit(face);
+
+        VectorizedArray<number> sigmaF =
+          std::abs((phi.normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]) *
+          (number)(std::max(1, fe_degree) * (fe_degree + 1.0)) * 2.;
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value = phi.get_value(q);
+                VectorizedArray<number> average_valgrad =
+                  -phi.get_normal_derivative(q);
+                average_valgrad += average_value * sigmaF * 2.0;
+                phi.submit_normal_derivative(-average_value, q);
+                phi.submit_value(average_valgrad, q);
+              }
+
+            phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+  int                                        fe_degree;
+};
+
+
+
+template <typename MATRIX, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MATRIX &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-7, false, false);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MATRIX *coarse_matrix;
+};
+
+
+
+template <int dim, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const unsigned int n_q_points_1d)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                mapping(n_q_points_1d);
+  LaplaceOperator<dim, number> fine_matrix;
+  fine_matrix.initialize(mapping, dof, n_q_points_1d);
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = LaplaceOperator<dim, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].initialize(mapping, dof, n_q_points_1d, level);
+
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 20.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer;
+  mg_transfer.build(dof, partitioners);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    ReductionControl control(30, 1e-20, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim>
+void
+test(const unsigned int fe_degree)
+{
+  for (unsigned int i = 5; i < 9 - fe_degree; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        dealii::Triangulation<dim>::none,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      // set boundary ids on boundaries to the number of the face
+      for (unsigned int face = 2; face < GeometryInfo<dim>::faces_per_cell;
+           ++face)
+        tria.begin()->face(face)->set_all_boundary_ids(face);
+
+      std::vector<
+        GridTools::PeriodicFacePair<typename Triangulation<dim>::cell_iterator>>
+        periodic_faces;
+      for (unsigned int d = 1; d < dim; ++d)
+        GridTools::collect_periodic_faces(
+          tria, 2 * d, 2 * d + 1, d, periodic_faces);
+      tria.add_periodicity(periodic_faces);
+
+      tria.refine_global(i - dim);
+
+      FE_DGQ<dim>     fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, double>(dof, fe_degree + 1);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+
+  {
+    deallog.push("2d");
+    test<2>(1);
+    test<2>(2);
+    deallog.pop();
+    deallog.push("3d");
+    test<3>(1);
+    test<3>(2);
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=1.output b/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..4624baa
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 7 value 1.80729e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 8 value 8.73511e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 8 value 4.57619e-10
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 7 value 1.07430e-09
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 8 value 1.87005e-10
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 4 value 7.99677e-17
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.27740e-11
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 7 value 2.41331e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 8 value 1.14978e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 9 value 1.16347e-09
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..7630f42
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 7 value 1.80729e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 8 value 8.73511e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 8 value 4.57619e-10
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 7 value 1.07430e-09
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 8 value 1.87005e-10
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 4 value 9.91449e-17
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.27740e-11
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 7 value 2.41331e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 8 value 1.14978e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 9 value 1.16347e-09
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=5.output b/tests/multigrid-global-coarsening/multigrid_dg_periodic.with_lapack=true.with_trilinos=true.with_p4est=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..e2e33e6
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 7 value 1.80729e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 8 value 8.73511e-11
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 8 value 4.57619e-10
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 7 value 1.07430e-09
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 8 value 1.87005e-10
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 4 value 7.23452e-17
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.27740e-11
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 7 value 2.41331e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 8 value 1.14978e-09
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 9 value 1.16347e-09
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_sip_01.cc b/tests/multigrid-global-coarsening/multigrid_dg_sip_01.cc
new file mode 100644 (file)
index 0000000..eabd921
--- /dev/null
@@ -0,0 +1,629 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2018 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test of a multigrid solver including face integration (DG case, symmetric
+// interior penalty + Nitsche).
+
+#include <deal.II/base/function.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <int dim, typename number = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &   mapping,
+             const DoFHandler<dim> &dof_handler,
+             const unsigned int     n_q_points_1d,
+             const unsigned int     level = numbers::invalid_unsigned_int)
+  {
+    fe_degree = dof_handler.get_fe().degree;
+
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    addit_data.mapping_update_flags_inner_faces =
+      (update_gradients | update_JxW_values);
+    addit_data.mapping_update_flags_boundary_faces =
+      (update_gradients | update_JxW_values);
+    AffineConstraints<double> constraints;
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    if (!src.partitioners_are_globally_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      {
+        LinearAlgebra::distributed::Vector<number> src_copy;
+        src_copy.reinit(data.get_dof_info().vector_partitioner);
+        src_copy = src;
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src).swap(
+          src_copy);
+      }
+    if (!dst.partitioners_are_globally_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      {
+        LinearAlgebra::distributed::Vector<number> dst_copy;
+        dst_copy.reinit(data.get_dof_info().vector_partitioner);
+        dst_copy = dst;
+        dst.swap(dst_copy);
+      }
+    dst.zero_out_ghost_values();
+    data.loop(&LaplaceOperator::local_apply,
+              &LaplaceOperator::local_apply_face,
+              &LaplaceOperator::local_apply_boundary,
+              this,
+              dst,
+              src);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    data.initialize_dof_vector(vector);
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    return inverse_diagonal_entries;
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_face(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval_neighbor(data, false);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval_neighbor.reinit(face);
+
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval_neighbor.read_dof_values(src);
+        fe_eval_neighbor.evaluate(EvaluationFlags::values |
+                                  EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          (std::abs((fe_eval.normal_vector(0) *
+                     fe_eval.inverse_jacobian(0))[dim - 1]) +
+           std::abs((fe_eval.normal_vector(0) *
+                     fe_eval_neighbor.inverse_jacobian(0))[dim - 1])) *
+          (number)(std::max(fe_degree, 1) * (fe_degree + 1.0));
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value =
+              (fe_eval.get_value(q) - fe_eval_neighbor.get_value(q)) * 0.5;
+            VectorizedArray<number> average_valgrad =
+              fe_eval.get_normal_derivative(q) +
+              fe_eval_neighbor.get_normal_derivative(q);
+            average_valgrad =
+              average_value * 2. * sigmaF - average_valgrad * 0.5;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval_neighbor.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+            fe_eval_neighbor.submit_value(-average_valgrad, q);
+          }
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+        fe_eval_neighbor.integrate(EvaluationFlags::values |
+                                   EvaluationFlags::gradients);
+        fe_eval_neighbor.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_boundary(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          std::abs(
+            (fe_eval.normal_vector(0) * fe_eval.inverse_jacobian(0))[dim - 1]) *
+          number(std::max(fe_degree, 1) * (fe_degree + 1.0)) * 2.0;
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value = fe_eval.get_value(q);
+            VectorizedArray<number> average_valgrad =
+              -fe_eval.get_normal_derivative(q);
+            average_valgrad += average_value * sigmaF * 2.0;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+          }
+
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.loop(&LaplaceOperator::local_diagonal_cell,
+              &LaplaceOperator::local_diagonal_face,
+              &LaplaceOperator::local_diagonal_boundary,
+              this,
+              inverse_diagonal_entries,
+              dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number>    phi(data);
+    AlignedVector<VectorizedArray<number>> local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_diagonal_face(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi(data, true);
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi_outer(data, false);
+    AlignedVector<VectorizedArray<number>>  local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        phi.reinit(face);
+        phi_outer.reinit(face);
+
+        VectorizedArray<number> sigmaF =
+          (std::abs((phi.normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]) +
+           std::abs(
+             (phi.normal_vector(0) * phi_outer.inverse_jacobian(0))[dim - 1])) *
+          (number)(std::max(fe_degree, 1) * (fe_degree + 1.0));
+
+        // Compute phi part
+        for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+          phi_outer.begin_dof_values()[j] = VectorizedArray<number>();
+        phi_outer.evaluate(EvaluationFlags::values |
+                           EvaluationFlags::gradients);
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value =
+                  (phi.get_value(q) - phi_outer.get_value(q)) * 0.5;
+                VectorizedArray<number> average_valgrad =
+                  phi.get_normal_derivative(q) +
+                  phi_outer.get_normal_derivative(q);
+                average_valgrad =
+                  average_value * 2. * sigmaF - average_valgrad * 0.5;
+                phi.submit_normal_derivative(-average_value, q);
+                phi.submit_value(average_valgrad, q);
+              }
+            phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+
+        // Compute phi_outer part
+        for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+          phi.begin_dof_values()[j] = VectorizedArray<number>();
+        phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi_outer.begin_dof_values()[j] = VectorizedArray<number>();
+            phi_outer.begin_dof_values()[i] = 1.;
+            phi_outer.evaluate(EvaluationFlags::values |
+                               EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value =
+                  (phi.get_value(q) - phi_outer.get_value(q)) * 0.5;
+                VectorizedArray<number> average_valgrad =
+                  phi.get_normal_derivative(q) +
+                  phi_outer.get_normal_derivative(q);
+                average_valgrad =
+                  average_value * 2. * sigmaF - average_valgrad * 0.5;
+                phi_outer.submit_normal_derivative(-average_value, q);
+                phi_outer.submit_value(-average_valgrad, q);
+              }
+            phi_outer.integrate(EvaluationFlags::values |
+                                EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi_outer.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi_outer.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi_outer.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_diagonal_boundary(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> phi(data);
+    AlignedVector<VectorizedArray<number>>  local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        phi.reinit(face);
+
+        VectorizedArray<number> sigmaF =
+          std::abs((phi.normal_vector(0) * phi.inverse_jacobian(0))[dim - 1]) *
+          number(std::max(fe_degree, 1) * (fe_degree + 1.0)) * 2.0;
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              {
+                VectorizedArray<number> average_value = phi.get_value(q);
+                VectorizedArray<number> average_valgrad =
+                  -phi.get_normal_derivative(q);
+                average_valgrad += average_value * sigmaF * 2.0;
+                phi.submit_normal_derivative(-average_value, q);
+                phi.submit_value(average_valgrad, q);
+              }
+
+            phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+  int                                        fe_degree;
+};
+
+
+
+template <typename MATRIX, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MATRIX &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10, false, false);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MATRIX *coarse_matrix;
+};
+
+
+
+template <int dim, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const unsigned n_q_points_1d)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                mapping(n_q_points_1d);
+  LaplaceOperator<dim, number> fine_matrix;
+  fine_matrix.initialize(mapping, dof, n_q_points_1d);
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = LaplaceOperator<dim, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, n_q_points_1d, level);
+    }
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 20.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+
+  mg_transfer.build(dof, [&](const unsigned int level, auto &vec) {
+    mg_matrices[level].initialize_dof_vector(vec);
+  });
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim>
+void
+test(const unsigned int fe_degree)
+{
+  for (unsigned int i = 5; i < 9 - fe_degree; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        dealii::Triangulation<dim>::none,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_DGQ<dim>     fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, double>(dof, fe_degree + 1);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+
+  {
+    deallog.push("2d");
+    test<2>(1);
+    test<2>(2);
+    deallog.pop();
+    deallog.push("3d");
+    test<3>(1);
+    test<3>(2);
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=1.output b/tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..3755b9b
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 5 value 3.60502e-07
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 5 value 2.14074e-06
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 5 value 5.99637e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 5 value 1.81901e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 6 value 1.94976e-07
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 6 value 7.43327e-08
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.28298e-06
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 6 value 5.09300e-06
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 6 value 1.73456e-07
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 7 value 5.35539e-07
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=5.output b/tests/multigrid-global-coarsening/multigrid_dg_sip_01.with_lapack=true.with_p4est=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..3755b9b
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 5 value 3.60502e-07
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 5 value 2.14074e-06
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 5 value 5.99637e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 5 value 1.81901e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 6 value 1.94976e-07
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 6 value 7.43327e-08
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.28298e-06
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 6 value 5.09300e-06
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 6 value 1.73456e-07
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 7 value 5.35539e-07
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_sip_02.cc b/tests/multigrid-global-coarsening/multigrid_dg_sip_02.cc
new file mode 100644 (file)
index 0000000..ff8c64f
--- /dev/null
@@ -0,0 +1,547 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2018 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test of a multigrid solver including face integration (DG case, symmetric
+// interior penalty + Nitsche). As opposed to multigrid_dg_sip_01, this test
+// computes the diagonal using the alternative reinit(cell_index, face_number)
+
+#include <deal.II/base/function.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_values.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <int dim, typename number = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &   mapping,
+             const DoFHandler<dim> &dof_handler,
+             const unsigned int     n_q_points_1d,
+             const unsigned int     level = numbers::invalid_unsigned_int)
+  {
+    fe_degree = dof_handler.get_fe().degree;
+
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    addit_data.mapping_update_flags_inner_faces =
+      update_JxW_values | update_normal_vectors | update_jacobians;
+    addit_data.mapping_update_flags_boundary_faces =
+      update_JxW_values | update_normal_vectors | update_jacobians;
+    addit_data.mapping_update_flags_faces_by_cells =
+      update_JxW_values | update_normal_vectors | update_jacobians;
+    AffineConstraints<double> constraints;
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    if (!src.partitioners_are_globally_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      {
+        LinearAlgebra::distributed::Vector<number> src_copy;
+        src_copy.reinit(data.get_dof_info().vector_partitioner);
+        src_copy = src;
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src).swap(
+          src_copy);
+      }
+    if (!dst.partitioners_are_globally_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      {
+        LinearAlgebra::distributed::Vector<number> dst_copy;
+        dst_copy.reinit(data.get_dof_info().vector_partitioner);
+        dst_copy = dst;
+        dst.swap(dst_copy);
+      }
+    dst.zero_out_ghost_values();
+    data.loop(&LaplaceOperator::local_apply,
+              &LaplaceOperator::local_apply_face,
+              &LaplaceOperator::local_apply_boundary,
+              this,
+              dst,
+              src);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    data.initialize_dof_vector(vector);
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_face(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval_neighbor(data, false);
+
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval_neighbor.reinit(face);
+
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval_neighbor.read_dof_values(src);
+        fe_eval_neighbor.evaluate(EvaluationFlags::values |
+                                  EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          (std::abs((fe_eval.normal_vector(0) *
+                     fe_eval.inverse_jacobian(0))[dim - 1]) +
+           std::abs((fe_eval.normal_vector(0) *
+                     fe_eval_neighbor.inverse_jacobian(0))[dim - 1])) *
+          (number)(std::max(fe_degree, 1) * (fe_degree + 1.0));
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value =
+              (fe_eval.get_value(q) - fe_eval_neighbor.get_value(q)) * 0.5;
+            VectorizedArray<number> average_valgrad =
+              fe_eval.get_normal_derivative(q) +
+              fe_eval_neighbor.get_normal_derivative(q);
+            average_valgrad =
+              average_value * 2. * sigmaF - average_valgrad * 0.5;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval_neighbor.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+            fe_eval_neighbor.submit_value(-average_valgrad, q);
+          }
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+        fe_eval_neighbor.integrate(EvaluationFlags::values |
+                                   EvaluationFlags::gradients);
+        fe_eval_neighbor.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  local_apply_boundary(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     face_range) const
+  {
+    FEFaceEvaluation<dim, -1, 0, 1, number> fe_eval(data, true);
+    for (unsigned int face = face_range.first; face < face_range.second; ++face)
+      {
+        fe_eval.reinit(face);
+        fe_eval.read_dof_values(src);
+        fe_eval.evaluate(EvaluationFlags::values | EvaluationFlags::gradients);
+        VectorizedArray<number> sigmaF =
+          std::abs(
+            (fe_eval.normal_vector(0) * fe_eval.inverse_jacobian(0))[dim - 1]) *
+          (number)(std::max(1, fe_degree) * (fe_degree + 1.0)) * 2.;
+
+        for (unsigned int q = 0; q < fe_eval.n_q_points; ++q)
+          {
+            VectorizedArray<number> average_value = fe_eval.get_value(q);
+            VectorizedArray<number> average_valgrad =
+              -fe_eval.get_normal_derivative(q);
+            average_valgrad += average_value * sigmaF * 2.0;
+            fe_eval.submit_normal_derivative(-average_value, q);
+            fe_eval.submit_value(average_valgrad, q);
+          }
+
+        fe_eval.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        fe_eval.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number>     phi(data);
+    FEFaceEvaluation<dim, -1, 0, 1, number> phif(data);
+    AlignedVector<VectorizedArray<number>>  local_diagonal_vector(
+      phi.dofs_per_cell);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (const unsigned int face : GeometryInfo<dim>::face_indices())
+          {
+            phif.reinit(cell, face);
+            VectorizedArray<number> sigmaF =
+              std::abs(
+                (phif.normal_vector(0) * phif.inverse_jacobian(0))[dim - 1]) *
+              (number)(std::max(1, fe_degree) * (fe_degree + 1.0)) * 2.;
+            std::array<types::boundary_id, VectorizedArray<number>::size()>
+              boundary_ids = data.get_faces_by_cells_boundary_id(cell, face);
+            VectorizedArray<number> factor_boundary;
+            for (unsigned int v = 0; v < VectorizedArray<number>::size(); ++v)
+              // interior face
+              if (boundary_ids[v] == numbers::invalid_boundary_id)
+                factor_boundary[v] = 0.5;
+              // Dirichlet boundary
+              else
+                factor_boundary[v] = 1.0;
+            for (unsigned int i = 0; i < phif.dofs_per_cell; ++i)
+              {
+                for (unsigned int j = 0; j < phif.dofs_per_cell; ++j)
+                  phif.begin_dof_values()[j] = VectorizedArray<number>();
+                phif.begin_dof_values()[i] = 1.;
+                phif.evaluate(EvaluationFlags::values |
+                              EvaluationFlags::gradients);
+                for (unsigned int q = 0; q < phif.n_q_points; ++q)
+                  {
+                    VectorizedArray<number> average_value =
+                      phif.get_value(q) * factor_boundary;
+                    VectorizedArray<number> average_valgrad =
+                      phif.get_normal_derivative(q) * factor_boundary;
+                    average_valgrad =
+                      average_value * 2. * sigmaF - average_valgrad;
+                    phif.submit_normal_derivative(-average_value, q);
+                    phif.submit_value(average_valgrad, q);
+                  }
+                phif.integrate(EvaluationFlags::values |
+                               EvaluationFlags::gradients);
+                local_diagonal_vector[i] += phif.begin_dof_values()[i];
+              }
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+  int                                        fe_degree;
+};
+
+
+
+template <typename MATRIX, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MATRIX &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10, false, false);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MATRIX *coarse_matrix;
+};
+
+
+
+template <int dim, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const unsigned int n_q_points_1d)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                mapping(n_q_points_1d);
+  LaplaceOperator<dim, number> fine_matrix;
+  fine_matrix.initialize(mapping, dof, n_q_points_1d);
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = LaplaceOperator<dim, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, n_q_points_1d, level);
+    }
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 20.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim>
+void
+test(const unsigned int fe_degree)
+{
+  for (unsigned int i = 5; i < 9 - fe_degree; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        dealii::Triangulation<dim>::none,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_DGQ<dim>     fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, double>(dof, fe_degree + 1);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    deallog.push("2d");
+    test<2>(1);
+    test<2>(2);
+    deallog.pop();
+    deallog.push("3d");
+    test<3>(1);
+    test<3>(2);
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/multigrid_dg_sip_02.with_lapack=true.with_p4est=true.mpirun=5.output b/tests/multigrid-global-coarsening/multigrid_dg_sip_02.with_lapack=true.with_p4est=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..3755b9b
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 256
+DEAL:2d:cg::Starting value 16.0000
+DEAL:2d:cg::Convergence step 5 value 3.60502e-07
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 1024
+DEAL:2d:cg::Starting value 32.0000
+DEAL:2d:cg::Convergence step 5 value 2.14074e-06
+DEAL:2d::Testing FE_DGQ<2>(1)
+DEAL:2d::Number of degrees of freedom: 4096
+DEAL:2d:cg::Starting value 64.0000
+DEAL:2d:cg::Convergence step 5 value 5.99637e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 576
+DEAL:2d:cg::Starting value 24.0000
+DEAL:2d:cg::Convergence step 5 value 1.81901e-06
+DEAL:2d::Testing FE_DGQ<2>(2)
+DEAL:2d::Number of degrees of freedom: 2304
+DEAL:2d:cg::Starting value 48.0000
+DEAL:2d:cg::Convergence step 6 value 1.94976e-07
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 512
+DEAL:3d:cg::Starting value 22.6274
+DEAL:3d:cg::Convergence step 6 value 7.43327e-08
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 4096
+DEAL:3d:cg::Starting value 64.0000
+DEAL:3d:cg::Convergence step 6 value 2.28298e-06
+DEAL:3d::Testing FE_DGQ<3>(1)
+DEAL:3d::Number of degrees of freedom: 32768
+DEAL:3d:cg::Starting value 181.019
+DEAL:3d:cg::Convergence step 6 value 5.09300e-06
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 1728
+DEAL:3d:cg::Starting value 41.5692
+DEAL:3d:cg::Convergence step 6 value 1.73456e-07
+DEAL:3d::Testing FE_DGQ<3>(2)
+DEAL:3d::Number of degrees of freedom: 13824
+DEAL:3d:cg::Starting value 117.576
+DEAL:3d:cg::Convergence step 7 value 5.35539e-07
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid.cc b/tests/multigrid-global-coarsening/parallel_multigrid.cc
new file mode 100644 (file)
index 0000000..5e5212d
--- /dev/null
@@ -0,0 +1,452 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test running a multigrid solver on continuous FE_Q finite elements with
+// MatrixFree data structures (otherwise similar to step-37)
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &                mapping,
+             const DoFHandler<dim> &             dof_handler,
+             const std::set<types::boundary_id> &dirichlet_boundaries,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.mg_level = level;
+
+    // extract the constraints due to Dirichlet boundary conditions
+    AffineConstraints<double>                           constraints;
+    Functions::ZeroFunction<dim>                        zero;
+    std::map<types::boundary_id, const Function<dim> *> functions;
+    for (std::set<types::boundary_id>::const_iterator it =
+           dirichlet_boundaries.begin();
+         it != dirichlet_boundaries.end();
+         ++it)
+      functions[*it] = &zero;
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, number> fine_matrix;
+  const std::set<types::boundary_id> dirichlet_boundaries = {0};
+  fine_matrix.initialize(mapping, dof, dirichlet_boundaries);
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, dirichlet_boundaries, level);
+    }
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer;
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner.reset(
+        new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+      smoother_data[level].preconditioner->get_vector() =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  for (unsigned int i = 5; i < 8; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    test<2, 2>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    test<3, 2>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..3d043ad
--- /dev/null
@@ -0,0 +1,145 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 81
+DEAL:2d:cg::Starting value 9.000
+DEAL:2d:cg:cg::Starting value 0.02203
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 0.0001585
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 8.884e-07
+DEAL:2d:cg:cg::Convergence step 1 value 9.863e-23
+DEAL:2d:cg:cg::Starting value 3.123e-09
+DEAL:2d:cg:cg::Convergence step 1 value 3.468e-25
+DEAL:2d:cg::Convergence step 4 value 2.071e-08
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 0.005310
+DEAL:2d:cg:cg::Convergence step 1 value 5.895e-19
+DEAL:2d:cg:cg::Starting value 5.163e-06
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 2.182e-08
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 9.610e-10
+DEAL:2d:cg:cg::Convergence step 1 value 2.134e-25
+DEAL:2d:cg::Convergence step 4 value 2.778e-08
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 0.008242
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 2.754e-06
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 9.820e-09
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 8.188e-12
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg::Convergence step 4 value 8.029e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 3.849
+DEAL:2d:cg:cg::Convergence step 2 value 1.388e-15
+DEAL:2d:cg:cg::Starting value 0.0007035
+DEAL:2d:cg:cg::Convergence step 2 value 7.914e-19
+DEAL:2d:cg:cg::Starting value 4.286e-06
+DEAL:2d:cg:cg::Convergence step 2 value 1.471e-21
+DEAL:2d:cg:cg::Starting value 2.909e-08
+DEAL:2d:cg:cg::Convergence step 2 value 1.896e-23
+DEAL:2d:cg::Convergence step 4 value 3.931e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 14.69
+DEAL:2d:cg:cg::Convergence step 2 value 4.242e-15
+DEAL:2d:cg:cg::Starting value 0.002915
+DEAL:2d:cg:cg::Convergence step 2 value 1.213e-18
+DEAL:2d:cg:cg::Starting value 3.439e-06
+DEAL:2d:cg:cg::Convergence step 2 value 1.583e-21
+DEAL:2d:cg:cg::Starting value 1.212e-08
+DEAL:2d:cg:cg::Convergence step 2 value 1.131e-24
+DEAL:2d:cg::Convergence step 4 value 8.121e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 4225
+DEAL:2d:cg::Starting value 65.00
+DEAL:2d:cg:cg::Starting value 58.09
+DEAL:2d:cg:cg::Convergence step 2 value 4.467e-14
+DEAL:2d:cg:cg::Starting value 0.01056
+DEAL:2d:cg:cg::Convergence step 2 value 9.358e-19
+DEAL:2d:cg:cg::Starting value 2.588e-05
+DEAL:2d:cg:cg::Convergence step 2 value 3.405e-20
+DEAL:2d:cg:cg::Starting value 6.672e-08
+DEAL:2d:cg:cg::Convergence step 2 value 5.007e-23
+DEAL:2d:cg::Convergence step 4 value 1.695e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 125
+DEAL:3d:cg::Starting value 11.18
+DEAL:3d:cg:cg::Starting value 0.5164
+DEAL:3d:cg:cg::Convergence step 1 value 1.147e-16
+DEAL:3d:cg:cg::Starting value 0.02357
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 5.322e-05
+DEAL:3d:cg:cg::Convergence step 1 value 1.182e-20
+DEAL:3d:cg:cg::Starting value 1.537e-07
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg::Convergence step 4 value 3.460e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 0.1824
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 0.004902
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 5.629e-06
+DEAL:3d:cg:cg::Convergence step 1 value 1.250e-21
+DEAL:3d:cg:cg::Starting value 3.386e-10
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg::Convergence step 4 value 1.074e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 0.1633
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 0.0001064
+DEAL:3d:cg:cg::Convergence step 1 value 1.181e-20
+DEAL:3d:cg:cg::Starting value 1.367e-06
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 1.607e-08
+DEAL:3d:cg:cg::Convergence step 1 value 3.568e-24
+DEAL:3d:cg::Convergence step 4 value 5.067e-08
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 1.696
+DEAL:3d:cg:cg::Convergence step 2 value 4.279e-16
+DEAL:3d:cg:cg::Starting value 0.1039
+DEAL:3d:cg:cg::Convergence step 2 value 1.250e-17
+DEAL:3d:cg:cg::Starting value 0.0001780
+DEAL:3d:cg:cg::Convergence step 2 value 1.054e-20
+DEAL:3d:cg:cg::Starting value 5.292e-06
+DEAL:3d:cg:cg::Convergence step 2 value 1.622e-22
+DEAL:3d:cg::Convergence step 4 value 2.351e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 2.288
+DEAL:3d:cg:cg::Convergence step 2 value 1.482e-15
+DEAL:3d:cg:cg::Starting value 0.04493
+DEAL:3d:cg:cg::Convergence step 2 value 2.411e-18
+DEAL:3d:cg:cg::Starting value 0.0007205
+DEAL:3d:cg:cg::Convergence step 2 value 9.281e-20
+DEAL:3d:cg:cg::Starting value 2.913e-06
+DEAL:3d:cg:cg::Convergence step 2 value 5.846e-23
+DEAL:3d:cg::Convergence step 4 value 4.578e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 35937
+DEAL:3d:cg::Starting value 189.6
+DEAL:3d:cg:cg::Starting value 17.19
+DEAL:3d:cg:cg::Convergence step 2 value 1.912e-14
+DEAL:3d:cg:cg::Starting value 0.01678
+DEAL:3d:cg:cg::Convergence step 2 value 4.151e-18
+DEAL:3d:cg:cg::Starting value 0.001099
+DEAL:3d:cg:cg::Convergence step 2 value 2.529e-19
+DEAL:3d:cg:cg::Starting value 9.998e-07
+DEAL:3d:cg:cg::Convergence step 2 value 5.098e-22
+DEAL:3d:cg::Convergence step 4 value 1.784e-05
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/multigrid-global-coarsening/parallel_multigrid.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..c7a1fdd
--- /dev/null
@@ -0,0 +1,145 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 81
+DEAL:2d:cg::Starting value 9.000
+DEAL:2d:cg:cg::Starting value 0.02203
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 0.0001585
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 8.884e-07
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 3.123e-09
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg::Convergence step 4 value 2.071e-08
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 0.005310
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 5.163e-06
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 2.182e-08
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 9.610e-10
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg::Convergence step 4 value 2.778e-08
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 0.008242
+DEAL:2d:cg:cg::Convergence step 1 value 1.830e-18
+DEAL:2d:cg:cg::Starting value 2.754e-06
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 9.820e-09
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg:cg::Starting value 8.188e-12
+DEAL:2d:cg:cg::Convergence step 1 value 0.000
+DEAL:2d:cg::Convergence step 4 value 8.029e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 3.849
+DEAL:2d:cg:cg::Convergence step 2 value 1.863e-15
+DEAL:2d:cg:cg::Starting value 0.0007035
+DEAL:2d:cg:cg::Convergence step 2 value 5.372e-19
+DEAL:2d:cg:cg::Starting value 4.286e-06
+DEAL:2d:cg:cg::Convergence step 2 value 4.258e-21
+DEAL:2d:cg:cg::Starting value 2.909e-08
+DEAL:2d:cg:cg::Convergence step 2 value 1.177e-24
+DEAL:2d:cg::Convergence step 4 value 3.931e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 14.69
+DEAL:2d:cg:cg::Convergence step 2 value 1.771e-14
+DEAL:2d:cg:cg::Starting value 0.002915
+DEAL:2d:cg:cg::Convergence step 2 value 2.794e-18
+DEAL:2d:cg:cg::Starting value 3.439e-06
+DEAL:2d:cg:cg::Convergence step 2 value 1.470e-21
+DEAL:2d:cg:cg::Starting value 1.212e-08
+DEAL:2d:cg:cg::Convergence step 2 value 4.310e-24
+DEAL:2d:cg::Convergence step 4 value 8.121e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 4225
+DEAL:2d:cg::Starting value 65.00
+DEAL:2d:cg:cg::Starting value 58.09
+DEAL:2d:cg:cg::Convergence step 2 value 7.517e-15
+DEAL:2d:cg:cg::Starting value 0.01056
+DEAL:2d:cg:cg::Convergence step 2 value 3.556e-18
+DEAL:2d:cg:cg::Starting value 2.588e-05
+DEAL:2d:cg:cg::Convergence step 2 value 1.590e-20
+DEAL:2d:cg:cg::Starting value 6.672e-08
+DEAL:2d:cg:cg::Convergence step 2 value 3.475e-23
+DEAL:2d:cg::Convergence step 4 value 1.695e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 125
+DEAL:3d:cg::Starting value 11.18
+DEAL:3d:cg:cg::Starting value 0.5164
+DEAL:3d:cg:cg::Convergence step 1 value 1.147e-16
+DEAL:3d:cg:cg::Starting value 0.02357
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 5.322e-05
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 1.537e-07
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg::Convergence step 4 value 3.460e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 0.1824
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 0.004902
+DEAL:3d:cg:cg::Convergence step 1 value 5.443e-19
+DEAL:3d:cg:cg::Starting value 5.629e-06
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 3.386e-10
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg::Convergence step 4 value 1.074e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 0.1633
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 0.0001064
+DEAL:3d:cg:cg::Convergence step 1 value 2.362e-20
+DEAL:3d:cg:cg::Starting value 1.367e-06
+DEAL:3d:cg:cg::Convergence step 1 value 0.000
+DEAL:3d:cg:cg::Starting value 1.607e-08
+DEAL:3d:cg:cg::Convergence step 1 value 3.568e-24
+DEAL:3d:cg::Convergence step 4 value 5.067e-08
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 1.696
+DEAL:3d:cg:cg::Convergence step 2 value 1.987e-16
+DEAL:3d:cg:cg::Starting value 0.1039
+DEAL:3d:cg:cg::Convergence step 2 value 3.578e-18
+DEAL:3d:cg:cg::Starting value 0.0001780
+DEAL:3d:cg:cg::Convergence step 2 value 1.311e-20
+DEAL:3d:cg:cg::Starting value 5.292e-06
+DEAL:3d:cg:cg::Convergence step 2 value 5.646e-22
+DEAL:3d:cg::Convergence step 4 value 2.351e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 2.288
+DEAL:3d:cg:cg::Convergence step 2 value 6.751e-17
+DEAL:3d:cg:cg::Starting value 0.04493
+DEAL:3d:cg:cg::Convergence step 2 value 1.105e-17
+DEAL:3d:cg:cg::Starting value 0.0007205
+DEAL:3d:cg:cg::Convergence step 2 value 1.525e-20
+DEAL:3d:cg:cg::Starting value 2.913e-06
+DEAL:3d:cg:cg::Convergence step 2 value 7.041e-22
+DEAL:3d:cg::Convergence step 4 value 4.578e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 35937
+DEAL:3d:cg::Starting value 189.6
+DEAL:3d:cg:cg::Starting value 17.19
+DEAL:3d:cg:cg::Convergence step 2 value 5.350e-15
+DEAL:3d:cg:cg::Starting value 0.01678
+DEAL:3d:cg:cg::Convergence step 2 value 3.272e-18
+DEAL:3d:cg:cg::Starting value 0.001099
+DEAL:3d:cg:cg::Convergence step 2 value 2.132e-20
+DEAL:3d:cg:cg::Starting value 9.998e-07
+DEAL:3d:cg:cg::Convergence step 2 value 3.927e-22
+DEAL:3d:cg::Convergence step 4 value 1.784e-05
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_02.cc b/tests/multigrid-global-coarsening/parallel_multigrid_02.cc
new file mode 100644 (file)
index 0000000..6e1bdfe
--- /dev/null
@@ -0,0 +1,291 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// similar to parallel_multigrid.cc but using
+// MatrixFreeOperators::LaplaceOperator class
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+using namespace dealii::MatrixFreeOperators;
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  LaplaceOperator<dim,
+                  fe_degree,
+                  n_q_points_1d,
+                  1,
+                  LinearAlgebra::distributed::Vector<number>>
+                                           fine_matrix;
+  std::shared_ptr<MatrixFree<dim, number>> fine_level_data(
+    new MatrixFree<dim, number>());
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim,
+                    fe_degree,
+                    n_q_points_1d,
+                    1,
+                    LinearAlgebra::distributed::Vector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.mg_level = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  for (unsigned int i = 5; i < 7; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    test<2, 2>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    test<3, 2>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..591de5b
--- /dev/null
@@ -0,0 +1,78 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 81
+DEAL:2d:cg::Starting value 9.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg::Convergence step 3 value 6.753e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg::Convergence step 4 value 2.625e-09
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 3.765
+DEAL:2d:cg:cg::Convergence step 1 value 2.359e-16
+DEAL:2d:cg:cg::Starting value 0.0005314
+DEAL:2d:cg:cg::Convergence step 1 value 6.437e-20
+DEAL:2d:cg:cg::Starting value 3.806e-06
+DEAL:2d:cg:cg::Convergence step 1 value 9.264e-23
+DEAL:2d:cg:cg::Starting value 1.628e-08
+DEAL:2d:cg:cg::Convergence step 1 value 1.034e-24
+DEAL:2d:cg::Convergence step 4 value 1.712e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 14.37
+DEAL:2d:cg:cg::Convergence step 1 value 8.327e-16
+DEAL:2d:cg:cg::Starting value 0.002280
+DEAL:2d:cg:cg::Convergence step 1 value 2.711e-20
+DEAL:2d:cg:cg::Starting value 6.550e-06
+DEAL:2d:cg:cg::Convergence step 1 value 1.570e-22
+DEAL:2d:cg:cg::Starting value 5.084e-08
+DEAL:2d:cg:cg::Convergence step 1 value 6.035e-24
+DEAL:2d:cg::Convergence step 4 value 4.315e-08
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 125
+DEAL:3d:cg::Starting value 11.18
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg::Convergence step 3 value 4.383e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg::Convergence step 3 value 1.025e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 0.3870
+DEAL:3d:cg:cg::Convergence step 1 value 4.005e-17
+DEAL:3d:cg:cg::Starting value 0.0005996
+DEAL:3d:cg:cg::Convergence step 1 value 2.717e-20
+DEAL:3d:cg:cg::Starting value 3.381e-07
+DEAL:3d:cg:cg::Convergence step 1 value 1.182e-23
+DEAL:3d:cg:cg::Starting value 5.601e-10
+DEAL:3d:cg:cg::Convergence step 1 value 5.638e-26
+DEAL:3d:cg::Convergence step 4 value 5.998e-09
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 2.248
+DEAL:3d:cg:cg::Convergence step 1 value 8.552e-17
+DEAL:3d:cg:cg::Starting value 0.0007474
+DEAL:3d:cg:cg::Convergence step 1 value 1.057e-19
+DEAL:3d:cg:cg::Starting value 3.260e-06
+DEAL:3d:cg:cg::Convergence step 1 value 4.268e-23
+DEAL:3d:cg:cg::Starting value 1.168e-08
+DEAL:3d:cg:cg::Convergence step 1 value 4.233e-25
+DEAL:3d:cg::Convergence step 4 value 5.811e-08
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/multigrid-global-coarsening/parallel_multigrid_02.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..f77b7fe
--- /dev/null
@@ -0,0 +1,78 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 81
+DEAL:2d:cg::Starting value 9.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg::Convergence step 3 value 6.753e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg:cg::Convergence step 0 value 0.000
+DEAL:2d:cg::Convergence step 4 value 2.625e-09
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 289
+DEAL:2d:cg::Starting value 17.00
+DEAL:2d:cg:cg::Starting value 3.765
+DEAL:2d:cg:cg::Convergence step 1 value 2.220e-16
+DEAL:2d:cg:cg::Starting value 0.0005314
+DEAL:2d:cg:cg::Convergence step 1 value 2.282e-20
+DEAL:2d:cg:cg::Starting value 3.806e-06
+DEAL:2d:cg:cg::Convergence step 1 value 2.569e-22
+DEAL:2d:cg:cg::Starting value 1.628e-08
+DEAL:2d:cg:cg::Convergence step 1 value 9.306e-25
+DEAL:2d:cg::Convergence step 4 value 1.712e-08
+DEAL:2d::Testing FE_Q<2>(2)
+DEAL:2d::Number of degrees of freedom: 1089
+DEAL:2d:cg::Starting value 33.00
+DEAL:2d:cg:cg::Starting value 14.37
+DEAL:2d:cg:cg::Convergence step 1 value 9.437e-16
+DEAL:2d:cg:cg::Starting value 0.002280
+DEAL:2d:cg:cg::Convergence step 1 value 2.168e-19
+DEAL:2d:cg:cg::Starting value 6.550e-06
+DEAL:2d:cg:cg::Convergence step 1 value 5.823e-22
+DEAL:2d:cg:cg::Starting value 5.084e-08
+DEAL:2d:cg:cg::Convergence step 1 value 4.136e-25
+DEAL:2d:cg::Convergence step 4 value 4.315e-08
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 125
+DEAL:3d:cg::Starting value 11.18
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg::Convergence step 3 value 4.383e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg:cg::Convergence step 0 value 0.000
+DEAL:3d:cg::Convergence step 3 value 1.025e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 729
+DEAL:3d:cg::Starting value 27.00
+DEAL:3d:cg:cg::Starting value 0.3870
+DEAL:3d:cg:cg::Convergence step 1 value 3.850e-18
+DEAL:3d:cg:cg::Starting value 0.0005996
+DEAL:3d:cg:cg::Convergence step 1 value 1.355e-20
+DEAL:3d:cg:cg::Starting value 3.381e-07
+DEAL:3d:cg:cg::Convergence step 1 value 8.779e-24
+DEAL:3d:cg:cg::Starting value 5.601e-10
+DEAL:3d:cg:cg::Convergence step 1 value 4.426e-26
+DEAL:3d:cg::Convergence step 4 value 5.998e-09
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 4913
+DEAL:3d:cg::Starting value 70.09
+DEAL:3d:cg:cg::Starting value 2.248
+DEAL:3d:cg:cg::Convergence step 1 value 2.463e-16
+DEAL:3d:cg:cg::Starting value 0.0007474
+DEAL:3d:cg:cg::Convergence step 1 value 1.924e-20
+DEAL:3d:cg:cg::Starting value 3.260e-06
+DEAL:3d:cg:cg::Convergence step 1 value 2.263e-22
+DEAL:3d:cg:cg::Starting value 1.168e-08
+DEAL:3d:cg:cg::Convergence step 1 value 1.617e-26
+DEAL:3d:cg::Convergence step 4 value 5.811e-08
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.cc
new file mode 100644 (file)
index 0000000..8071a10
--- /dev/null
@@ -0,0 +1,645 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// similar as parallel_multigrid but using adaptive meshes with hanging nodes
+// (doing local smoothing)
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  LaplaceOperator(){};
+
+
+  void
+  initialize(const Mapping<dim> &     mapping,
+             const DoFHandler<dim> &  dof_handler,
+             const MGConstrainedDoFs &mg_constrained_dofs,
+             const std::map<types::boundary_id, const Function<dim> *>
+               &                dirichlet_boundary,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    AffineConstraints<double> constraints;
+    if (level == numbers::invalid_unsigned_int)
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_dofs(dof_handler, relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+        VectorTools::interpolate_boundary_values(dof_handler,
+                                                 dirichlet_boundary,
+                                                 constraints);
+      }
+    else
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_level_dofs(dof_handler,
+                                                      level,
+                                                      relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        constraints.add_lines(mg_constrained_dofs.get_boundary_indices(level));
+
+        const std::vector<types::global_dof_index> interface_indices =
+          mg_constrained_dofs.get_refinement_edge_indices(level)
+            .get_index_vector();
+        edge_constrained_indices.clear();
+        edge_constrained_indices.reserve(interface_indices.size());
+        edge_constrained_values.resize(interface_indices.size());
+        const IndexSet &locally_owned =
+          dof_handler.locally_owned_mg_dofs(level);
+        for (unsigned int i = 0; i < interface_indices.size(); ++i)
+          if (locally_owned.is_element(interface_indices[i]))
+            edge_constrained_indices.push_back(
+              locally_owned.index_within_set(interface_indices[i]));
+        have_interface_matrices =
+          Utilities::MPI::max((unsigned int)edge_constrained_indices.size(),
+                              MPI_COMM_WORLD) > 0;
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    if (level != numbers::invalid_unsigned_int)
+      compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        edge_constrained_values[i] = std::pair<number, number>(
+          src.local_element(edge_constrained_indices[i]),
+          dst.local_element(edge_constrained_indices[i]));
+        const_cast<LinearAlgebra::distributed::Vector<double> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+
+    // reset edge constrained values, multiply by unit matrix and add into
+    // destination
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const_cast<LinearAlgebra::distributed::Vector<double> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+        dst.local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].second + edge_constrained_values[i].first;
+      }
+  }
+
+  void
+  vmult_interface_down(
+    LinearAlgebra::distributed::Vector<double> &      dst,
+    const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const double src_val = src.local_element(edge_constrained_indices[i]);
+        const_cast<LinearAlgebra::distributed::Vector<double> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+        edge_constrained_values[i] = std::pair<number, number>(
+          src_val, dst.local_element(edge_constrained_indices[i]));
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    unsigned int c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          dst.local_element(c) = 0.;
+        ++c;
+
+        // reset the src values
+        const_cast<LinearAlgebra::distributed::Vector<double> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+      }
+    for (; c < dst.locally_owned_size(); ++c)
+      dst.local_element(c) = 0.;
+  }
+
+  void
+  vmult_interface_up(
+    LinearAlgebra::distributed::Vector<double> &      dst,
+    const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    LinearAlgebra::distributed::Vector<double> src_cpy(src);
+    unsigned int                               c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          src_cpy.local_element(c) = 0.;
+        ++c;
+      }
+    for (; c < src_cpy.locally_owned_size(); ++c)
+      src_cpy.local_element(c) = 0.;
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src_cpy);
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        dst.local_element(edge_constrained_indices[i]) = 0.;
+      }
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      inverse_diagonal_entries.local_element(constrained_dofs[i]) = 1.;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        inverse_diagonal_entries.local_element(edge_constrained_indices[i]) =
+          1.;
+      }
+
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                        data;
+  LinearAlgebra::distributed::Vector<number>     inverse_diagonal_entries;
+  std::vector<unsigned int>                      edge_constrained_indices;
+  mutable std::vector<std::pair<number, number>> edge_constrained_values;
+  bool                                           have_interface_matrices;
+};
+
+
+
+template <typename LAPLACEOPERATOR>
+class MGInterfaceMatrix : public Subscriptor
+{
+public:
+  void
+  initialize(const LAPLACEOPERATOR &laplace)
+  {
+    this->laplace = &laplace;
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<double> &      dst,
+        const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    laplace->vmult_interface_down(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<double> &      dst,
+         const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    laplace->vmult_interface_up(dst, src);
+  }
+
+private:
+  SmartPointer<const LAPLACEOPERATOR> laplace;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  AffineConstraints<double> hanging_node_constraints;
+  IndexSet                  locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+  hanging_node_constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+  hanging_node_constraints.close();
+
+  MGConstrainedDoFs                                   mg_constrained_dofs;
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, number> fine_matrix;
+  fine_matrix.initialize(mapping,
+                         dof,
+                         mg_constrained_dofs,
+                         dirichlet_boundary,
+                         numbers::invalid_unsigned_int);
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+    if (!hanging_node_constraints.is_constrained(
+          in.get_partitioner()->local_to_global(i)))
+      in.local_element(i) = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(
+        mapping, dof, mg_constrained_dofs, dirichlet_boundary, level);
+    }
+  MGLevelObject<MGInterfaceMatrix<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner.reset(
+        new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+      smoother_data[level].preconditioner->get_vector() =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..4e020c6
--- /dev/null
@@ -0,0 +1,29 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 5 value 1.167e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 6 value 1.190e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 6 value 1.886e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 6 value 3.143e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 6 value 2.139e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 7 value 4.724e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 8 value 6.234e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_01.with_p4est=true.with_trilinos=true.with_lapack=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..cd898e3
--- /dev/null
@@ -0,0 +1,29 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 5 value 1.145e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 6 value 1.176e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 6 value 1.884e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 6 value 3.090e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 6 value 2.139e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 7 value 4.739e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 8 value 6.236e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.cc
new file mode 100644 (file)
index 0000000..3e528fb
--- /dev/null
@@ -0,0 +1,333 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// same as parallel_multigrid_adaptive_01, but based on MGTransferMatrixFree
+// and using MatrixFreeOperators::LaplaceOperator class.
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  LaplaceOperator<dim,
+                  fe_degree,
+                  n_q_points_1d,
+                  1,
+                  LinearAlgebra::distributed::Vector<number>>
+                                           fine_matrix;
+  std::shared_ptr<MatrixFree<dim, number>> fine_level_data(
+    new MatrixFree<dim, number>());
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  {
+    // this is to make it consistent with parallel_multigrid_adaptive.cc
+    AffineConstraints<double> hanging_node_constraints;
+    hanging_node_constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+    hanging_node_constraints.close();
+
+    for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+      if (!hanging_node_constraints.is_constrained(
+            in.get_partitioner()->local_to_global(i)))
+        in.local_element(i) = 1.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim,
+                    fe_degree,
+                    n_q_points_1d,
+                    1,
+                    LinearAlgebra::distributed::Vector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_level_data[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    test<2, 3>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    test<3, 2>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..57d068d
--- /dev/null
@@ -0,0 +1,49 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 5 value 1.167e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 6 value 1.190e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 6 value 1.886e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 6 value 3.143e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 64.26
+DEAL:2d:cg::Convergence step 5 value 2.131e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 83.11
+DEAL:2d:cg::Convergence step 6 value 5.783e-07
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 131.0
+DEAL:2d:cg::Convergence step 6 value 6.147e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 6 value 2.139e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 7 value 4.724e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 8 value 6.234e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 82.90
+DEAL:3d:cg::Convergence step 7 value 1.038e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 152.6
+DEAL:3d:cg::Convergence step 7 value 4.360e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=7.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_02.with_p4est=true.with_lapack=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..e5e72f2
--- /dev/null
@@ -0,0 +1,49 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 5 value 1.145e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 6 value 1.176e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 6 value 1.884e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 6 value 3.090e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 64.26
+DEAL:2d:cg::Convergence step 5 value 2.131e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 83.11
+DEAL:2d:cg::Convergence step 6 value 5.788e-07
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 131.0
+DEAL:2d:cg::Convergence step 6 value 6.134e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 6 value 2.139e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 7 value 4.739e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 8 value 6.236e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 82.90
+DEAL:3d:cg::Convergence step 7 value 1.039e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 152.6
+DEAL:3d:cg::Convergence step 7 value 4.352e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.cc
new file mode 100644 (file)
index 0000000..7aff6d4
--- /dev/null
@@ -0,0 +1,651 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// same test as parallel_multigrid_adaptive_01 but using
+// MGTransferMatrixFree rather the MGTransferPrebuilt (and manually
+// implementing the full LaplaceOperator class rather than using the
+// operator as in _02)
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+
+  void
+  initialize(const Mapping<dim> &     mapping,
+             const DoFHandler<dim> &  dof_handler,
+             const MGConstrainedDoFs &mg_constrained_dofs,
+             const std::map<types::boundary_id, const Function<dim> *>
+               &                dirichlet_boundary,
+             const unsigned int level,
+             const bool         threaded)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    if (threaded)
+      addit_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::partition_partition;
+    else
+      addit_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    AffineConstraints<double> constraints;
+    if (level == numbers::invalid_unsigned_int)
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_dofs(dof_handler, relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+        VectorTools::interpolate_boundary_values(dof_handler,
+                                                 dirichlet_boundary,
+                                                 constraints);
+      }
+    else
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_level_dofs(dof_handler,
+                                                      level,
+                                                      relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        constraints.add_lines(mg_constrained_dofs.get_boundary_indices(level));
+
+        const std::vector<types::global_dof_index> interface_indices =
+          mg_constrained_dofs.get_refinement_edge_indices(level)
+            .get_index_vector();
+        edge_constrained_indices.clear();
+        edge_constrained_indices.reserve(interface_indices.size());
+        edge_constrained_values.resize(interface_indices.size());
+        const IndexSet &locally_owned =
+          dof_handler.locally_owned_mg_dofs(level);
+        for (unsigned int i = 0; i < interface_indices.size(); ++i)
+          if (locally_owned.is_element(interface_indices[i]))
+            edge_constrained_indices.push_back(
+              locally_owned.index_within_set(interface_indices[i]));
+        have_interface_matrices =
+          Utilities::MPI::max((unsigned int)edge_constrained_indices.size(),
+                              MPI_COMM_WORLD) > 0;
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    if (level != numbers::invalid_unsigned_int)
+      compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        edge_constrained_values[i] = std::pair<number, number>(
+          src.local_element(edge_constrained_indices[i]),
+          dst.local_element(edge_constrained_indices[i]));
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+
+    // reset edge constrained values, multiply by unit matrix and add into
+    // destination
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+        dst.local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].second + edge_constrained_values[i].first;
+      }
+  }
+
+  void
+  vmult_interface_down(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const double src_val = src.local_element(edge_constrained_indices[i]);
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+        edge_constrained_values[i] = std::pair<number, number>(
+          src_val, dst.local_element(edge_constrained_indices[i]));
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    unsigned int c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          dst.local_element(c) = 0.;
+        ++c;
+
+        // reset the src values
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+      }
+    for (; c < dst.locally_owned_size(); ++c)
+      dst.local_element(c) = 0.;
+  }
+
+  void
+  vmult_interface_up(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    LinearAlgebra::distributed::Vector<number> src_cpy(src);
+    unsigned int                               c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          src_cpy.local_element(c) = 0.;
+        ++c;
+      }
+    for (; c < src_cpy.locally_owned_size(); ++c)
+      src_cpy.local_element(c) = 0.;
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src_cpy);
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        dst.local_element(edge_constrained_indices[i]) = 0.;
+      }
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      inverse_diagonal_entries.local_element(constrained_dofs[i]) = 1.;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        inverse_diagonal_entries.local_element(edge_constrained_indices[i]) =
+          1.;
+      }
+
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                        data;
+  LinearAlgebra::distributed::Vector<number>     inverse_diagonal_entries;
+  std::vector<unsigned int>                      edge_constrained_indices;
+  mutable std::vector<std::pair<number, number>> edge_constrained_values;
+  bool                                           have_interface_matrices;
+};
+
+
+
+template <typename LAPLACEOPERATOR>
+class MGInterfaceMatrix : public Subscriptor
+{
+public:
+  void
+  initialize(const LAPLACEOPERATOR &laplace)
+  {
+    this->laplace = &laplace;
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<typename LAPLACEOPERATOR::value_type>
+          &dst,
+        const LinearAlgebra::distributed::Vector<
+          typename LAPLACEOPERATOR::value_type> &src) const
+  {
+    laplace->vmult_interface_down(dst, src);
+  }
+
+  void
+  Tvmult(
+    LinearAlgebra::distributed::Vector<typename LAPLACEOPERATOR::value_type>
+      &dst,
+    const LinearAlgebra::distributed::Vector<
+      typename LAPLACEOPERATOR::value_type> &src) const
+  {
+    laplace->vmult_interface_up(dst, src);
+  }
+
+private:
+  SmartPointer<const LAPLACEOPERATOR> laplace;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const bool threaded)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  AffineConstraints<double> hanging_node_constraints;
+  IndexSet                  locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+  hanging_node_constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+  hanging_node_constraints.close();
+
+  MGConstrainedDoFs                                   mg_constrained_dofs;
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, double> fine_matrix;
+  fine_matrix.initialize(mapping,
+                         dof,
+                         mg_constrained_dofs,
+                         dirichlet_boundary,
+                         numbers::invalid_unsigned_int,
+                         threaded);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+    if (!hanging_node_constraints.is_constrained(
+          in.get_partitioner()->local_to_global(i)))
+      in.local_element(i) = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(
+        mapping, dof, mg_constrained_dofs, dirichlet_boundary, level, threaded);
+    }
+  MGLevelObject<MGInterfaceMatrix<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner.reset(
+        new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+      smoother_data[level].preconditioner->get_vector() =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim, int fe_degree, typename Number>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(8 - 2 * dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      deallog.push("nothread");
+      do_test<dim, fe_degree, fe_degree + 1, Number>(dof, false);
+      deallog.pop();
+      deallog.push("threaded");
+      do_test<dim, fe_degree, fe_degree + 1, Number>(dof, true);
+      deallog.pop();
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc,
+                                            argv,
+                                            testing_max_num_threads());
+
+  mpi_initlog();
+
+  test<2, 1, double>();
+  test<2, 2, float>();
+  test<3, 1, double>();
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.with_p4est=true.with_lapack=true.mpirun=4.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_03.with_p4est=true.with_lapack=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..3959556
--- /dev/null
@@ -0,0 +1,81 @@
+
+DEAL:nothread::Testing FE_Q<2>(1)
+DEAL:nothread::Number of degrees of freedom: 507
+DEAL:nothread:cg::Starting value 21.9317
+DEAL:nothread:cg::Convergence step 5 value 1.14537e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 507
+DEAL:threaded:cg::Starting value 21.9317
+DEAL:threaded:cg::Convergence step 5 value 1.14537e-06
+DEAL:nothread::Testing FE_Q<2>(1)
+DEAL:nothread::Number of degrees of freedom: 881
+DEAL:nothread:cg::Starting value 27.7669
+DEAL:nothread:cg::Convergence step 6 value 1.18996e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 881
+DEAL:threaded:cg::Starting value 27.7669
+DEAL:threaded:cg::Convergence step 6 value 1.18996e-06
+DEAL:nothread::Testing FE_Q<2>(1)
+DEAL:nothread::Number of degrees of freedom: 2147
+DEAL:nothread:cg::Starting value 43.2551
+DEAL:nothread:cg::Convergence step 6 value 1.86235e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 2147
+DEAL:threaded:cg::Starting value 43.2551
+DEAL:threaded:cg::Convergence step 6 value 1.86235e-06
+DEAL:nothread::Testing FE_Q<2>(1)
+DEAL:nothread::Number of degrees of freedom: 6517
+DEAL:nothread:cg::Starting value 76.9220
+DEAL:nothread:cg::Convergence step 6 value 3.14118e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 6517
+DEAL:threaded:cg::Starting value 76.9220
+DEAL:threaded:cg::Convergence step 6 value 3.14118e-06
+DEAL:nothread::Testing FE_Q<2>(2)
+DEAL:nothread::Number of degrees of freedom: 1935
+DEAL:nothread:cg::Starting value 43.0929
+DEAL:nothread:cg::Convergence step 5 value 3.22499e-06
+DEAL:threaded::Testing FE_Q<2>(2)
+DEAL:threaded::Number of degrees of freedom: 1935
+DEAL:threaded:cg::Starting value 43.0929
+DEAL:threaded:cg::Convergence step 5 value 3.22490e-06
+DEAL:nothread::Testing FE_Q<2>(2)
+DEAL:nothread::Number of degrees of freedom: 3403
+DEAL:nothread:cg::Starting value 55.4346
+DEAL:nothread:cg::Convergence step 6 value 8.67842e-07
+DEAL:threaded::Testing FE_Q<2>(2)
+DEAL:threaded::Number of degrees of freedom: 3403
+DEAL:threaded:cg::Starting value 55.4346
+DEAL:threaded:cg::Convergence step 6 value 8.67877e-07
+DEAL:nothread::Testing FE_Q<2>(2)
+DEAL:nothread::Number of degrees of freedom: 8417
+DEAL:nothread:cg::Starting value 87.1149
+DEAL:nothread:cg::Convergence step 6 value 5.47729e-07
+DEAL:threaded::Testing FE_Q<2>(2)
+DEAL:threaded::Number of degrees of freedom: 8417
+DEAL:threaded:cg::Starting value 87.1149
+DEAL:threaded:cg::Convergence step 6 value 5.47731e-07
+DEAL:nothread::Testing FE_Q<3>(1)
+DEAL:nothread::Number of degrees of freedom: 186
+DEAL:nothread:cg::Starting value 12.3693
+DEAL:nothread:cg::Convergence step 4 value 2.87808e-08
+DEAL:threaded::Testing FE_Q<3>(1)
+DEAL:threaded::Number of degrees of freedom: 186
+DEAL:threaded:cg::Starting value 12.3693
+DEAL:threaded:cg::Convergence step 4 value 2.87808e-08
+DEAL:nothread::Testing FE_Q<3>(1)
+DEAL:nothread::Number of degrees of freedom: 648
+DEAL:nothread:cg::Starting value 21.1424
+DEAL:nothread:cg::Convergence step 6 value 6.44935e-07
+DEAL:threaded::Testing FE_Q<3>(1)
+DEAL:threaded::Number of degrees of freedom: 648
+DEAL:threaded:cg::Starting value 21.1424
+DEAL:threaded:cg::Convergence step 6 value 6.44935e-07
+DEAL:nothread::Testing FE_Q<3>(1)
+DEAL:nothread::Number of degrees of freedom: 2930
+DEAL:nothread:cg::Starting value 47.1699
+DEAL:nothread:cg::Convergence step 7 value 2.56010e-06
+DEAL:threaded::Testing FE_Q<3>(1)
+DEAL:threaded::Number of degrees of freedom: 2930
+DEAL:threaded:cg::Starting value 47.1699
+DEAL:threaded:cg::Convergence step 7 value 2.56010e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.cc
new file mode 100644 (file)
index 0000000..185f0d5
--- /dev/null
@@ -0,0 +1,330 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// same as parallel_multigrid_adaptive_02, but using mg::SmootherRelaxation
+// rather than MGSmootherPrecondition
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  LaplaceOperator<dim,
+                  fe_degree,
+                  n_q_points_1d,
+                  1,
+                  LinearAlgebra::distributed::Vector<number>>
+                                           fine_matrix;
+  std::shared_ptr<MatrixFree<dim, number>> fine_level_data(
+    new MatrixFree<dim, number>());
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  {
+    // this is to make it consistent with parallel_multigrid_adaptive.cc
+    AffineConstraints<double> hanging_node_constraints;
+    hanging_node_constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+    hanging_node_constraints.close();
+
+    for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+      if (!hanging_node_constraints.is_constrained(
+            in.get_partitioner()->local_to_global(i)))
+        in.local_element(i) = 1.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim,
+                    fe_degree,
+                    n_q_points_1d,
+                    1,
+                    LinearAlgebra::distributed::Vector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_level_data[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  mg::SmootherRelaxation<SMOOTHER, LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<double>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(8 - 2 * dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_04.with_p4est=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..e189620
--- /dev/null
@@ -0,0 +1,15 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 186
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 648
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 2930
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.cc
new file mode 100644 (file)
index 0000000..287b2fd
--- /dev/null
@@ -0,0 +1,643 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// same test as parallel_multigrid_adaptive_03 but using partition_color
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+
+  void
+  initialize(const Mapping<dim> &     mapping,
+             const DoFHandler<dim> &  dof_handler,
+             const MGConstrainedDoFs &mg_constrained_dofs,
+             const std::map<types::boundary_id, const Function<dim> *>
+               &                dirichlet_boundary,
+             const unsigned int level,
+             const bool         threaded)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    if (threaded)
+      addit_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::partition_color;
+    else
+      addit_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.tasks_block_size = 3;
+    addit_data.mg_level         = level;
+    AffineConstraints<double> constraints;
+    if (level == numbers::invalid_unsigned_int)
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_dofs(dof_handler, relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+        VectorTools::interpolate_boundary_values(dof_handler,
+                                                 dirichlet_boundary,
+                                                 constraints);
+      }
+    else
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_level_dofs(dof_handler,
+                                                      level,
+                                                      relevant_dofs);
+        constraints.reinit(relevant_dofs);
+        constraints.add_lines(mg_constrained_dofs.get_boundary_indices(level));
+
+        const std::vector<types::global_dof_index> interface_indices =
+          mg_constrained_dofs.get_refinement_edge_indices(level)
+            .get_index_vector();
+        edge_constrained_indices.clear();
+        edge_constrained_indices.reserve(interface_indices.size());
+        edge_constrained_values.resize(interface_indices.size());
+        const IndexSet &locally_owned =
+          dof_handler.locally_owned_mg_dofs(level);
+        for (unsigned int i = 0; i < interface_indices.size(); ++i)
+          if (locally_owned.is_element(interface_indices[i]))
+            edge_constrained_indices.push_back(
+              locally_owned.index_within_set(interface_indices[i]));
+        have_interface_matrices =
+          Utilities::MPI::max((unsigned int)edge_constrained_indices.size(),
+                              MPI_COMM_WORLD) > 0;
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    if (level != numbers::invalid_unsigned_int)
+      compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        edge_constrained_values[i] = std::pair<number, number>(
+          src.local_element(edge_constrained_indices[i]),
+          dst.local_element(edge_constrained_indices[i]));
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+
+    // reset edge constrained values, multiply by unit matrix and add into
+    // destination
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+        dst.local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].second + edge_constrained_values[i].first;
+      }
+  }
+
+  void
+  vmult_interface_down(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    // set zero Dirichlet values on the input vector (and remember the src and
+    // dst values because we need to reset them at the end)
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        const double src_val = src.local_element(edge_constrained_indices[i]);
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) = 0.;
+        edge_constrained_values[i] = std::pair<number, number>(
+          src_val, dst.local_element(edge_constrained_indices[i]));
+      }
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    unsigned int c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          dst.local_element(c) = 0.;
+        ++c;
+
+        // reset the src values
+        const_cast<LinearAlgebra::distributed::Vector<number> &>(src)
+          .local_element(edge_constrained_indices[i]) =
+          edge_constrained_values[i].first;
+      }
+    for (; c < dst.locally_owned_size(); ++c)
+      dst.local_element(c) = 0.;
+  }
+
+  void
+  vmult_interface_up(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    Assert(src.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+    Assert(dst.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+
+    dst = 0;
+
+    if (!have_interface_matrices)
+      return;
+
+    LinearAlgebra::distributed::Vector<number> src_cpy(src);
+    unsigned int                               c = 0;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        for (; c < edge_constrained_indices[i]; ++c)
+          src_cpy.local_element(c) = 0.;
+        ++c;
+      }
+    for (; c < src_cpy.locally_owned_size(); ++c)
+      src_cpy.local_element(c) = 0.;
+
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src_cpy);
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        dst.local_element(edge_constrained_indices[i]) = 0.;
+      }
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      inverse_diagonal_entries.local_element(constrained_dofs[i]) = 1.;
+    for (unsigned int i = 0; i < edge_constrained_indices.size(); ++i)
+      {
+        inverse_diagonal_entries.local_element(edge_constrained_indices[i]) =
+          1.;
+      }
+
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                        data;
+  LinearAlgebra::distributed::Vector<number>     inverse_diagonal_entries;
+  std::vector<unsigned int>                      edge_constrained_indices;
+  mutable std::vector<std::pair<number, number>> edge_constrained_values;
+  bool                                           have_interface_matrices;
+};
+
+
+
+template <typename LAPLACEOPERATOR>
+class MGInterfaceMatrix : public Subscriptor
+{
+public:
+  void
+  initialize(const LAPLACEOPERATOR &laplace)
+  {
+    this->laplace = &laplace;
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<typename LAPLACEOPERATOR::value_type>
+          &dst,
+        const LinearAlgebra::distributed::Vector<
+          typename LAPLACEOPERATOR::value_type> &src) const
+  {
+    laplace->vmult_interface_down(dst, src);
+  }
+
+  void
+  Tvmult(
+    LinearAlgebra::distributed::Vector<typename LAPLACEOPERATOR::value_type>
+      &dst,
+    const LinearAlgebra::distributed::Vector<
+      typename LAPLACEOPERATOR::value_type> &src) const
+  {
+    laplace->vmult_interface_up(dst, src);
+  }
+
+private:
+  SmartPointer<const LAPLACEOPERATOR> laplace;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const bool threaded)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  AffineConstraints<double> hanging_node_constraints;
+  IndexSet                  locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+  hanging_node_constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+  hanging_node_constraints.close();
+
+  MGConstrainedDoFs                                   mg_constrained_dofs;
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, double> fine_matrix;
+  fine_matrix.initialize(mapping,
+                         dof,
+                         mg_constrained_dofs,
+                         dirichlet_boundary,
+                         numbers::invalid_unsigned_int,
+                         threaded);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+    if (!hanging_node_constraints.is_constrained(
+          in.get_partitioner()->local_to_global(i)))
+      in.local_element(i) = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(
+        mapping, dof, mg_constrained_dofs, dirichlet_boundary, level, threaded);
+    }
+  MGLevelObject<MGInterfaceMatrix<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, double> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner.reset(
+        new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+      smoother_data[level].preconditioner->get_vector() =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, double>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim, int fe_degree, typename Number>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(8 - 2 * dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      deallog.push("threaded");
+      do_test<dim, fe_degree, fe_degree + 1, Number>(dof, true);
+      deallog.pop();
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  // The original issue with partition_color
+  // is hit with 2 threads and 4 cores.
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 2);
+
+  mpi_initlog();
+
+  test<2, 1, double>();
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.with_p4est=true.with_lapack=true.mpirun=4.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_05.with_p4est=true.with_lapack=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..5563de9
--- /dev/null
@@ -0,0 +1,17 @@
+
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 507
+DEAL:threaded:cg::Starting value 21.9317
+DEAL:threaded:cg::Convergence step 5 value 1.14537e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 881
+DEAL:threaded:cg::Starting value 27.7669
+DEAL:threaded:cg::Convergence step 6 value 1.18996e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 2147
+DEAL:threaded:cg::Starting value 43.2551
+DEAL:threaded:cg::Convergence step 6 value 1.86235e-06
+DEAL:threaded::Testing FE_Q<2>(1)
+DEAL:threaded::Number of degrees of freedom: 6517
+DEAL:threaded:cg::Starting value 76.9220
+DEAL:threaded:cg::Convergence step 6 value 3.14118e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.cc
new file mode 100644 (file)
index 0000000..d97e05d
--- /dev/null
@@ -0,0 +1,455 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// similar to parallel_multigrid_adaptive_06ref but using
+// MGTransferBlockMatrixFree to solve block-diagonal matrix with Laplace
+// operator on diagonals. As expected, when we use a block vector with a single
+// block, we get the same results as the reference, non-block solution, i.e.
+//
+// DEAL:2d:cg::Starting value 21.93
+// DEAL:2d:cg::Convergence step 7 value 1.961e-07
+//
+//
+// What this test is really for is block operations. As expected we see
+// exactly the same number of iterations and the ratio of \sqrt(2) in values,
+// i.e.
+//
+// DEAL:2d:cg::Starting value 31.02
+// DEAL:2d:cg::Convergence step 7 value 2.774e-07
+
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+/**
+ * Block-Laplace operator with Block vector.
+ */
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename BlockVectorType =
+            LinearAlgebra::distributed::BlockVector<double>>
+class BlockLaplace : public Subscriptor
+{
+public:
+  using value_type = typename BlockVectorType::value_type;
+  using size_type  = typename BlockVectorType::size_type;
+
+  BlockLaplace()
+    : Subscriptor()
+  {}
+
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, value_type>> data)
+  {
+    laplace.initialize(data);
+  }
+
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, value_type>> data,
+             const MGConstrainedDoFs &mg_constrained_dofs,
+             const unsigned int       level)
+  {
+    laplace.initialize(data, mg_constrained_dofs, level);
+  }
+
+  void
+  vmult_interface_down(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.vmult_interface_down(dst.block(b), src.block(b));
+  }
+
+  void
+  vmult_interface_up(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.vmult_interface_up(dst.block(b), src.block(b));
+  }
+
+  void
+  vmult(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.vmult(dst.block(b), src.block(b));
+  }
+
+  void
+  Tvmult(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.Tvmult(dst.block(b), src.block(b));
+  }
+
+  void
+  vmult_add(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.vmult_add(dst.block(b), src.block(b));
+  }
+
+  void
+  Tvmult_add(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.Tvmult_add(dst.block(b), src.block(b));
+  }
+
+  void
+  precondition_Jacobi(BlockVectorType &      dst,
+                      const BlockVectorType &src,
+                      const value_type       omega) const
+  {
+    for (unsigned int b = 0; b < src.n_blocks(); ++b)
+      laplace.precondition_Jacobi(dst.block(b), src.block(b), omega);
+  }
+
+  void
+  compute_diagonal()
+  {
+    laplace.compute_diagonal();
+  }
+
+
+  virtual void
+  clear()
+  {
+    laplace.clear();
+  }
+
+private:
+  MatrixFreeOperators::LaplaceOperator<dim,
+                                       fe_degree,
+                                       n_q_points_1d,
+                                       1,
+                                       typename BlockVectorType::BlockType>
+    laplace;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::BlockVector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                     level,
+             LinearAlgebra::distributed::BlockVector<Number> &      dst,
+             const LinearAlgebra::distributed::BlockVector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::BlockVector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof, const unsigned int nb)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  BlockLaplace<dim,
+               fe_degree,
+               n_q_points_1d,
+               LinearAlgebra::distributed::BlockVector<number>>
+                                           fine_matrix;
+  std::shared_ptr<MatrixFree<dim, number>> fine_level_data(
+    new MatrixFree<dim, number>());
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> in(nb), sol(nb);
+  for (unsigned int b = 0; b < nb; ++b)
+    {
+      fine_level_data->initialize_dof_vector(in.block(b));
+      fine_level_data->initialize_dof_vector(sol.block(b));
+    }
+
+  in.collect_sizes();
+  sol.collect_sizes();
+
+  // set constant rhs vector
+  {
+    // this is to make it consistent with parallel_multigrid_adaptive.cc
+    AffineConstraints<double> hanging_node_constraints;
+    hanging_node_constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+    hanging_node_constraints.close();
+
+    for (unsigned int i = 0; i < in.block(0).locally_owned_size(); ++i)
+      if (!hanging_node_constraints.is_constrained(
+            in.block(0).get_partitioner()->local_to_global(i)))
+        in.block(0).local_element(i) = 1.;
+
+    for (unsigned int b = 1; b < nb; ++b)
+      in.block(b) = in.block(0);
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    BlockLaplace<dim,
+                 fe_degree,
+                 n_q_points_1d,
+                 LinearAlgebra::distributed::BlockVector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  MGTransferBlockMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER = PreconditionJacobi<LevelMatrixType>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::BlockVector<number>>
+    mg_smoother;
+
+  mg_smoother.initialize(mg_matrices, typename SMOOTHER::AdditionalData(0.8));
+
+  mg::Matrix<LinearAlgebra::distributed::BlockVector<number>> mg_matrix(
+    mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::BlockVector<number>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::BlockVector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::BlockVector<number>,
+                 MGTransferBlockMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::BlockVector<number>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test(const unsigned int nbands = 1)
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof, nbands);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    test<2, 3>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    test<3, 2>();
+    deallog.pop();
+  }
+
+  // 2 blocks
+  {
+    deallog.push("2d");
+    test<2, 1>(2);
+    test<2, 3>(2);
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>(2);
+    test<3, 2>(2);
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..322c18c
--- /dev/null
@@ -0,0 +1,97 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 7 value 1.961e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 8 value 2.956e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 7 value 2.063e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 7 value 7.253e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 64.26
+DEAL:2d:cg::Convergence step 9 value 1.536e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 83.11
+DEAL:2d:cg::Convergence step 9 value 8.264e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 131.0
+DEAL:2d:cg::Convergence step 9 value 1.071e-05
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 8 value 3.711e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 8 value 5.151e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 9 value 6.124e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 82.90
+DEAL:3d:cg::Convergence step 9 value 3.485e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 152.6
+DEAL:3d:cg::Convergence step 10 value 2.494e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 31.02
+DEAL:2d:cg::Convergence step 7 value 2.774e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 39.27
+DEAL:2d:cg::Convergence step 8 value 4.180e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 61.17
+DEAL:2d:cg::Convergence step 7 value 2.918e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 108.8
+DEAL:2d:cg::Convergence step 7 value 1.026e-05
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 90.87
+DEAL:2d:cg::Convergence step 9 value 2.172e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 117.5
+DEAL:2d:cg::Convergence step 9 value 1.169e-05
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 185.2
+DEAL:2d:cg::Convergence step 9 value 1.515e-05
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 44.14
+DEAL:3d:cg::Convergence step 8 value 5.248e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 77.78
+DEAL:3d:cg::Convergence step 8 value 7.285e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 107.7
+DEAL:3d:cg::Convergence step 9 value 8.661e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 117.2
+DEAL:3d:cg::Convergence step 9 value 4.929e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 215.8
+DEAL:3d:cg::Convergence step 10 value 3.527e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.cc
new file mode 100644 (file)
index 0000000..5e84d27
--- /dev/null
@@ -0,0 +1,322 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// same as parallel_multigrid_adaptive_02, but with Jacobi smoother.
+// The only reason for this test is to provide a reference for
+// parallel_multigrid_adaptive_06
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<double> &      dst,
+             const LinearAlgebra::distributed::Vector<double> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  LaplaceOperator<dim,
+                  fe_degree,
+                  n_q_points_1d,
+                  1,
+                  LinearAlgebra::distributed::Vector<number>>
+                                           fine_matrix;
+  std::shared_ptr<MatrixFree<dim, number>> fine_level_data(
+    new MatrixFree<dim, number>());
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+
+  LinearAlgebra::distributed::Vector<number> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  {
+    // this is to make it consistent with parallel_multigrid_adaptive.cc
+    AffineConstraints<double> hanging_node_constraints;
+    hanging_node_constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+    hanging_node_constraints.close();
+
+    for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+      if (!hanging_node_constraints.is_constrained(
+            in.get_partitioner()->local_to_global(i)))
+        in.local_element(i) = 1.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim,
+                    fe_degree,
+                    n_q_points_1d,
+                    1,
+                    LinearAlgebra::distributed::Vector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_level_data[level].get_vector_partitioner());
+
+  MGTransferGlobalCoarsening<dim, LinearAlgebra::distributed::Vector<double>>
+    mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER = PreconditionJacobi<LevelMatrixType>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<double>>
+    mg_smoother;
+
+  mg_smoother.initialize(mg_matrices, typename SMOOTHER::AdditionalData(0.8));
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<double>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<double>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<
+    dim,
+    LinearAlgebra::distributed::Vector<double>,
+    MGTransferGlobalCoarsening<dim, LinearAlgebra::distributed::Vector<double>>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  {
+    deallog.push("2d");
+    test<2, 1>();
+    test<2, 3>();
+    deallog.pop();
+    deallog.push("3d");
+    test<3, 1>();
+    test<3, 2>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_06ref.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..8ca8213
--- /dev/null
@@ -0,0 +1,49 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 21.93
+DEAL:2d:cg::Convergence step 7 value 1.961e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 27.77
+DEAL:2d:cg::Convergence step 8 value 2.956e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 43.26
+DEAL:2d:cg::Convergence step 7 value 2.063e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 76.92
+DEAL:2d:cg::Convergence step 7 value 7.253e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 64.26
+DEAL:2d:cg::Convergence step 9 value 1.536e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 83.11
+DEAL:2d:cg::Convergence step 9 value 8.264e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 131.0
+DEAL:2d:cg::Convergence step 9 value 1.071e-05
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 31.21
+DEAL:3d:cg::Convergence step 8 value 3.711e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 55.00
+DEAL:3d:cg::Convergence step 8 value 5.151e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 76.18
+DEAL:3d:cg::Convergence step 9 value 6.124e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 82.90
+DEAL:3d:cg::Convergence step 9 value 3.485e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 152.6
+DEAL:3d:cg::Convergence step 10 value 2.494e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.cc
new file mode 100644 (file)
index 0000000..a08337b
--- /dev/null
@@ -0,0 +1,496 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// This test is similar to parallel_multigrid_adaptive_06 but we also test
+// for different polynomial degree in different blocks.
+// We expect to have the same iteration numbers as in
+// parallel_multigrid_adaptive_06 with repsect to the highest polynomial
+// degree used.
+
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include <algorithm>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+/**
+ * Block-Laplace operator with Block vector.
+ */
+template <int dim,
+          int fe_degree_1,
+          int fe_degree_2,
+          int n_q_points_1d,
+          typename BlockVectorType =
+            LinearAlgebra::distributed::BlockVector<double>>
+class BlockLaplace : public Subscriptor
+{
+public:
+  using value_type = typename BlockVectorType::value_type;
+  using size_type  = typename BlockVectorType::size_type;
+
+  BlockLaplace()
+    : Subscriptor()
+  {}
+
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, value_type>> data)
+  {
+    laplace1.initialize(data, std::vector<unsigned int>(1, 0));
+    laplace2.initialize(data, std::vector<unsigned int>(1, 1));
+  }
+
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, value_type>> data,
+             const std::vector<MGConstrainedDoFs> &mg_constrained_dofs,
+             const unsigned int                    level)
+  {
+    laplace1.initialize(data,
+                        mg_constrained_dofs[0],
+                        level,
+                        std::vector<unsigned int>(1, 0));
+    laplace2.initialize(data,
+                        mg_constrained_dofs[1],
+                        level,
+                        std::vector<unsigned int>(1, 1));
+  }
+
+  void
+  vmult_interface_down(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.vmult_interface_down(dst.block(0), src.block(0));
+    laplace2.vmult_interface_down(dst.block(1), src.block(1));
+  }
+
+  void
+  vmult_interface_up(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.vmult_interface_up(dst.block(0), src.block(0));
+    laplace2.vmult_interface_up(dst.block(1), src.block(1));
+  }
+
+  void
+  vmult(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.vmult(dst.block(0), src.block(0));
+    laplace2.vmult(dst.block(1), src.block(1));
+  }
+
+  void
+  Tvmult(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.Tvmult(dst.block(0), src.block(0));
+    laplace2.Tvmult(dst.block(1), src.block(1));
+  }
+
+  void
+  vmult_add(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.vmult_add(dst.block(0), src.block(0));
+    laplace2.vmult_add(dst.block(1), src.block(1));
+  }
+
+  void
+  Tvmult_add(BlockVectorType &dst, const BlockVectorType &src) const
+  {
+    laplace1.Tvmult_add(dst.block(0), src.block(0));
+    laplace2.Tvmult_add(dst.block(1), src.block(1));
+  }
+
+  void
+  precondition_Jacobi(BlockVectorType &      dst,
+                      const BlockVectorType &src,
+                      const value_type       omega) const
+  {
+    laplace1.precondition_Jacobi(dst.block(0), src.block(0), omega);
+    laplace2.precondition_Jacobi(dst.block(1), src.block(1), omega);
+  }
+
+  void
+  compute_diagonal()
+  {
+    laplace1.compute_diagonal();
+    laplace2.compute_diagonal();
+  }
+
+
+  virtual void
+  clear()
+  {
+    laplace1.clear();
+    laplace2.clear();
+  }
+
+private:
+  MatrixFreeOperators::LaplaceOperator<dim,
+                                       fe_degree_1,
+                                       n_q_points_1d,
+                                       1,
+                                       typename BlockVectorType::BlockType>
+    laplace1;
+  MatrixFreeOperators::LaplaceOperator<dim,
+                                       fe_degree_2,
+                                       n_q_points_1d,
+                                       1,
+                                       typename BlockVectorType::BlockType>
+    laplace2;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::BlockVector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                     level,
+             LinearAlgebra::distributed::BlockVector<Number> &      dst,
+             const LinearAlgebra::distributed::BlockVector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::BlockVector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim,
+          int fe_degree_1,
+          int fe_degree_2,
+          int n_q_points_1d,
+          typename number>
+void
+do_test(const std::vector<const DoFHandler<dim> *> &dof)
+{
+  const unsigned int nb = 2;
+  if (std::is_same_v<number, float> == true)
+    {
+      deallog.push("float");
+    }
+  else
+    {}
+
+  for (unsigned int i = 0; i < dof.size(); ++i)
+    {
+      deallog << "Testing " << dof[i]->get_fe().get_name();
+      deallog << std::endl;
+      deallog << "Number of degrees of freedom: " << dof[i]->n_dofs()
+              << std::endl;
+    }
+
+  std::vector<IndexSet> locally_relevant_dofs(dof.size());
+  for (unsigned int i = 0; i < dof.size(); ++i)
+    DoFTools::extract_locally_relevant_dofs(*dof[i], locally_relevant_dofs[i]);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  std::vector<AffineConstraints<double>>         constraints(dof.size());
+  std::vector<const AffineConstraints<double> *> constraints_ptrs(dof.size());
+  for (unsigned int i = 0; i < dof.size(); ++i)
+    {
+      constraints[i].reinit(locally_relevant_dofs[i]);
+      DoFTools::make_hanging_node_constraints(*dof[i], constraints[i]);
+      VectorTools::interpolate_boundary_values(*dof[i],
+                                               dirichlet_boundary,
+                                               constraints[i]);
+      constraints[i].close();
+      constraints_ptrs[i] = &constraints[i];
+    }
+  QGauss<1>     quad(n_q_points_1d);
+  constexpr int max_degree = std::max(fe_degree_1, fe_degree_2);
+  MappingQ<dim> mapping(max_degree);
+
+  typename MatrixFree<dim, number>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, number>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+
+  std::shared_ptr<MatrixFree<dim, double>> fine_level_data(
+    new MatrixFree<dim, double>());
+  fine_level_data->reinit(
+    mapping, dof, constraints_ptrs, quad, fine_level_additional_data);
+
+  BlockLaplace<dim,
+               fe_degree_1,
+               fe_degree_2,
+               n_q_points_1d,
+               LinearAlgebra::distributed::BlockVector<number>>
+    fine_matrix;
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> in(nb), sol(nb);
+  for (unsigned int b = 0; b < nb; ++b)
+    {
+      fine_level_data->initialize_dof_vector(in.block(b), b);
+      fine_level_data->initialize_dof_vector(sol.block(b), b);
+    }
+
+  in.collect_sizes();
+  sol.collect_sizes();
+
+  // set constant rhs vector
+  {
+    for (unsigned int b = 0; b < nb; ++b)
+      {
+        // this is to make it consistent with parallel_multigrid_adaptive.cc
+        AffineConstraints<double> hanging_node_constraints;
+
+        hanging_node_constraints.reinit(locally_relevant_dofs[b]);
+        DoFTools::make_hanging_node_constraints(*dof[b],
+                                                hanging_node_constraints);
+        hanging_node_constraints.close();
+
+        for (unsigned int i = 0; i < in.block(b).locally_owned_size(); ++i)
+          if (!hanging_node_constraints.is_constrained(
+                in.block(b).get_partitioner()->local_to_global(i)))
+            in.block(b).local_element(i) = 1.;
+      }
+  }
+
+  // level constraints:
+  std::vector<MGConstrainedDoFs> mg_constrained_dofs(dof.size());
+  for (unsigned int i = 0; i < dof.size(); ++i)
+    {
+      mg_constrained_dofs[i].initialize(*dof[i]);
+      mg_constrained_dofs[i].make_zero_boundary_constraints(*dof[i], {0});
+    }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    BlockLaplace<dim,
+                 fe_degree_1,
+                 fe_degree_2,
+                 n_q_points_1d,
+                 LinearAlgebra::distributed::BlockVector<number>>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof[0]->get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof[0]->get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof[0]->get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      std::vector<AffineConstraints<double>> level_constraints(dof.size());
+      std::vector<const AffineConstraints<double> *> level_constraints_ptrs(
+        dof.size());
+      for (unsigned int i = 0; i < dof.size(); ++i)
+        {
+          IndexSet relevant_dofs;
+          DoFTools::extract_locally_relevant_level_dofs(*dof[i],
+                                                        level,
+                                                        relevant_dofs);
+          level_constraints[i].reinit(relevant_dofs);
+          level_constraints[i].add_lines(
+            mg_constrained_dofs[i].get_boundary_indices(level));
+          level_constraints[i].close();
+          level_constraints_ptrs[i] = &level_constraints[i];
+        }
+
+      mg_level_data[level].reinit(
+        mapping, dof, level_constraints_ptrs, quad, mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof[0]->get_triangulation().n_global_levels() -
+                                 1);
+  for (unsigned int level = 0;
+       level < dof[0]->get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  MGTransferBlockMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER = PreconditionJacobi<LevelMatrixType>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::BlockVector<number>>
+    mg_smoother;
+
+  mg_smoother.initialize(mg_matrices, typename SMOOTHER::AdditionalData(0.8));
+
+  mg::Matrix<LinearAlgebra::distributed::BlockVector<number>> mg_matrix(
+    mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::BlockVector<number>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::BlockVector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::BlockVector<number>,
+                 MGTransferBlockMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::BlockVector<number>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  if (std::is_same_v<number, float> == true)
+    deallog.pop();
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof[0]->get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree_1, int fe_degree_2>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  constexpr int      max_degree = std::max(fe_degree_1, fe_degree_2);
+  const unsigned int n_runs     = max_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            (((cell->center().norm() < 0.5 &&
+               (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+              (dim == 2 && cell->center().norm() > 1.2))))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe_1(fe_degree_1);
+      DoFHandler<dim> dof_1(tria);
+      dof_1.distribute_dofs(fe_1);
+      dof_1.distribute_mg_dofs();
+
+      FE_Q<dim>       fe_2(fe_degree_2);
+      DoFHandler<dim> dof_2(tria);
+      dof_2.distribute_dofs(fe_2);
+      dof_2.distribute_mg_dofs();
+
+      std::vector<const DoFHandler<dim, dim> *> dh_ptrs{&dof_1, &dof_2};
+
+      constexpr int n_q_points_1d = std::max(fe_degree_1, fe_degree_2) + 1;
+      do_test<dim, fe_degree_1, fe_degree_2, n_q_points_1d, double>(dh_ptrs);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog();
+  deallog << std::setprecision(4);
+
+  // 2 blocks
+  {
+    deallog.push("2d");
+    test<2, 1, 1>();
+    deallog << std::endl;
+    test<2, 1, 3>();
+    deallog << std::endl;
+    test<2, 3, 1>();
+    deallog.pop();
+    deallog << std::endl;
+    deallog.push("3d");
+    test<3, 1, 1>();
+    deallog << std::endl;
+    test<3, 1, 2>();
+    deallog << std::endl;
+    test<3, 2, 1>();
+    deallog.pop();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_07.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..158a6bc
--- /dev/null
@@ -0,0 +1,108 @@
+
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 31.02
+DEAL:2d:cg::Convergence step 7 value 2.774e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 39.27
+DEAL:2d:cg::Convergence step 8 value 4.180e-07
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 61.17
+DEAL:2d:cg::Convergence step 7 value 2.918e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 6517
+DEAL:2d:cg::Starting value 108.8
+DEAL:2d:cg::Convergence step 7 value 1.026e-05
+DEAL:2d::
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d:cg::Starting value 67.90
+DEAL:2d:cg::Convergence step 9 value 1.556e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d:cg::Starting value 87.62
+DEAL:2d:cg::Convergence step 9 value 8.294e-06
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d:cg::Starting value 137.9
+DEAL:2d:cg::Convergence step 9 value 1.073e-05
+DEAL:2d::
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 4259
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 507
+DEAL:2d:cg::Starting value 67.90
+DEAL:2d:cg::Convergence step 9 value 1.556e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 7457
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 881
+DEAL:2d:cg::Starting value 87.62
+DEAL:2d:cg::Convergence step 9 value 8.294e-06
+DEAL:2d::Testing FE_Q<2>(3)
+DEAL:2d::Number of degrees of freedom: 18535
+DEAL:2d::Testing FE_Q<2>(1)
+DEAL:2d::Number of degrees of freedom: 2147
+DEAL:2d:cg::Starting value 137.9
+DEAL:2d:cg::Convergence step 9 value 1.073e-05
+DEAL::
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 44.14
+DEAL:3d:cg::Convergence step 8 value 5.248e-07
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 77.78
+DEAL:3d:cg::Convergence step 8 value 7.285e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 9566
+DEAL:3d:cg::Starting value 107.7
+DEAL:3d:cg::Convergence step 9 value 8.661e-06
+DEAL:3d::
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d:cg::Starting value 88.58
+DEAL:3d:cg::Convergence step 9 value 3.537e-06
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d:cg::Starting value 162.2
+DEAL:3d:cg::Convergence step 10 value 2.508e-06
+DEAL:3d::
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 7494
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 1103
+DEAL:3d:cg::Starting value 88.58
+DEAL:3d:cg::Convergence step 9 value 3.537e-06
+DEAL:3d::Testing FE_Q<3>(2)
+DEAL:3d::Number of degrees of freedom: 26548
+DEAL:3d::Testing FE_Q<3>(1)
+DEAL:3d::Number of degrees of freedom: 3694
+DEAL:3d:cg::Starting value 162.2
+DEAL:3d:cg::Convergence step 10 value 2.508e-06
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.cc b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.cc
new file mode 100644 (file)
index 0000000..5a24c48
--- /dev/null
@@ -0,0 +1,429 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// similar to parallel_multigrid_adaptive_02 but without using a separate
+// transfer class that builds the appropriate vectors. Furthermore, we want to
+// avoid setting some vectors to zero in the cell loop. Rather,
+// MatrixFreeOperators::LaplaceOperator::adjust_ghost_range_if_necessary()
+// will do that - or rather a variant of that, given that we want to modify
+// the cell loop of the LaplaceOperator class and provide our own. This forces
+// us to reimplement a few things, but all ideas are the same as in the
+// matrix-free operators.
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+using namespace dealii::MatrixFreeOperators;
+
+
+template <int dim, int fe_degree, typename Number>
+class MyLaplaceOperator : public MatrixFreeOperators::LaplaceOperator<
+                            dim,
+                            fe_degree,
+                            fe_degree + 1,
+                            1,
+                            LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, Number>> data,
+             const MGConstrainedDoFs &                      mg_constrained_dofs,
+             const unsigned int                             level)
+  {
+    MatrixFreeOperators::Base<dim, LinearAlgebra::distributed::Vector<Number>>::
+      initialize(data,
+                 mg_constrained_dofs,
+                 level,
+                 std::vector<unsigned int>({0}));
+
+    const std::vector<types::global_dof_index> interface_indices =
+      mg_constrained_dofs.get_refinement_edge_indices(level).get_index_vector();
+    vmult_edge_constrained_indices.clear();
+    vmult_edge_constrained_indices.reserve(interface_indices.size());
+    vmult_edge_constrained_values.resize(interface_indices.size());
+    const IndexSet &locally_owned =
+      this->data->get_dof_handler(0).locally_owned_mg_dofs(level);
+    for (unsigned int i = 0; i < interface_indices.size(); ++i)
+      if (locally_owned.is_element(interface_indices[i]))
+        vmult_edge_constrained_indices.push_back(
+          locally_owned.index_within_set(interface_indices[i]));
+  }
+
+  void
+  initialize(std::shared_ptr<const MatrixFree<dim, Number>> data,
+             const std::vector<unsigned int> &              mask = {})
+  {
+    MatrixFreeOperators::Base<dim, LinearAlgebra::distributed::Vector<Number>>::
+      initialize(data, mask);
+  }
+
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<Number> &      dst,
+        const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    adjust_ghost_range_if_necessary(src);
+    adjust_ghost_range_if_necessary(dst);
+
+    for (unsigned int i = 0; i < vmult_edge_constrained_indices.size(); ++i)
+      {
+        vmult_edge_constrained_values[i] =
+          src.local_element(vmult_edge_constrained_indices[i]);
+        const_cast<LinearAlgebra::distributed::Vector<Number> &>(src)
+          .local_element(vmult_edge_constrained_indices[i]) = 0.;
+      }
+
+    // zero dst within the loop
+    this->data->cell_loop(
+      &MyLaplaceOperator::local_apply, this, dst, src, true);
+
+    for (auto i : this->data->get_constrained_dofs(0))
+      dst.local_element(i) = src.local_element(i);
+    for (unsigned int i = 0; i < vmult_edge_constrained_indices.size(); ++i)
+      {
+        dst.local_element(vmult_edge_constrained_indices[i]) =
+          vmult_edge_constrained_values[i];
+        const_cast<LinearAlgebra::distributed::Vector<Number> &>(src)
+          .local_element(vmult_edge_constrained_indices[i]) =
+          vmult_edge_constrained_values[i];
+      }
+  }
+
+private:
+  void
+  local_apply(const MatrixFree<dim, Number> &                   data,
+              LinearAlgebra::distributed::Vector<Number> &      dst,
+              const LinearAlgebra::distributed::Vector<Number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, fe_degree + 1, 1, Number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.gather_evaluate(src, EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate_scatter(EvaluationFlags::gradients, dst);
+      }
+  }
+
+  void
+  adjust_ghost_range_if_necessary(
+    const LinearAlgebra::distributed::Vector<Number> &vec) const
+  {
+    if (vec.get_partitioner().get() ==
+        this->data->get_dof_info(0).vector_partitioner.get())
+      return;
+
+    Assert(
+      vec.get_partitioner()->locally_owned_size() ==
+        this->data->get_dof_info(0).vector_partitioner->locally_owned_size(),
+      ExcMessage("The vector passed to the vmult() function does not have "
+                 "the correct size for compatibility with MatrixFree."));
+    LinearAlgebra::distributed::Vector<Number> copy_vec(vec);
+    this->data->initialize_dof_vector(
+      const_cast<LinearAlgebra::distributed::Vector<Number> &>(vec), 0);
+    const_cast<LinearAlgebra::distributed::Vector<Number> &>(vec)
+      .copy_locally_owned_data_from(copy_vec);
+  }
+
+  std::vector<unsigned int> vmult_edge_constrained_indices;
+
+  mutable std::vector<double> vmult_edge_constrained_values;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  // level constraints:
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  MappingQ<dim> mapping(fe_degree + 1);
+
+  MyLaplaceOperator<dim, fe_degree, double> fine_matrix;
+  std::shared_ptr<MatrixFree<dim, double>>  fine_level_data(
+    new MatrixFree<dim, double>());
+
+  typename MatrixFree<dim, double>::AdditionalData fine_level_additional_data;
+  fine_level_additional_data.tasks_parallel_scheme =
+    MatrixFree<dim, double>::AdditionalData::none;
+  fine_level_additional_data.tasks_block_size = 3;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+  fine_matrix.compute_diagonal();
+
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  {
+    // this is to make it consistent with parallel_multigrid_adaptive.cc
+    AffineConstraints<double> hanging_node_constraints;
+    hanging_node_constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof, hanging_node_constraints);
+    hanging_node_constraints.close();
+
+    for (unsigned int i = 0; i < in.locally_owned_size(); ++i)
+      if (!hanging_node_constraints.is_constrained(
+            in.get_partitioner()->local_to_global(i)))
+        in.local_element(i) = 1.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = MyLaplaceOperator<dim, fe_degree, number>;
+
+  MGLevelObject<LevelMatrixType>         mg_matrices;
+  MGLevelObject<MatrixFree<dim, number>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reinit(mapping,
+                                  dof,
+                                  level_constraints,
+                                  QGauss<1>(n_q_points_1d),
+                                  mg_additional_data);
+      mg_matrices[level].initialize(std::make_shared<MatrixFree<dim, number>>(
+                                      mg_level_data[level]),
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+  MGLevelObject<MGInterfaceOperator<LevelMatrixType>> mg_interface_matrices;
+  mg_interface_matrices.resize(0,
+                               dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_interface_matrices[level].initialize(mg_matrices[level]);
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_level_data[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 6;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_interface(
+    mg_interface_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  mg.set_edge_matrices(mg_interface, mg_interface);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(3);
+
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  fine_matrix.clear();
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].clear();
+}
+
+
+
+template <int dim, int fe_degree>
+void
+test()
+{
+  parallel::distributed::Triangulation<dim> tria(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tria);
+  tria.refine_global(6 - dim);
+  const unsigned int n_runs = fe_degree == 1 ? 6 - dim : 5 - dim;
+  for (unsigned int i = 0; i < n_runs; ++i)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tria.begin_active();
+           cell != tria.end();
+           ++cell)
+        if (cell->is_locally_owned() &&
+            ((cell->center().norm() < 0.5 &&
+              (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+             (dim == 2 && cell->center().norm() > 1.2)))
+          cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, double>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  mpi_initlog(true);
+
+  test<2, 2>();
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_adaptive_08.with_p4est=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..f00e1a4
--- /dev/null
@@ -0,0 +1,47 @@
+
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 1935
+DEAL:cg::Starting value 43.0929
+DEAL:cg:cg::Starting value 2.63785
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 0.000574845
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 4.62010e-05
+DEAL:cg:cg::Convergence step 1 value 6.77626e-21
+DEAL:cg:cg::Starting value 6.27180e-07
+DEAL:cg:cg::Convergence step 1 value 1.05879e-22
+DEAL:cg:cg::Starting value 3.19916e-08
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg::Convergence step 5 value 2.10775e-06
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 3403
+DEAL:cg::Starting value 55.4346
+DEAL:cg:cg::Starting value 3.96150
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 0.00121318
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 9.44668e-05
+DEAL:cg:cg::Convergence step 1 value 1.35525e-20
+DEAL:cg:cg::Starting value 1.80128e-06
+DEAL:cg:cg::Convergence step 1 value 2.11758e-22
+DEAL:cg:cg::Starting value 1.21766e-07
+DEAL:cg:cg::Convergence step 1 value 2.64698e-23
+DEAL:cg:cg::Starting value 5.04178e-09
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg::Convergence step 6 value 4.24128e-07
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 8417
+DEAL:cg::Starting value 87.1149
+DEAL:cg:cg::Starting value 9.09582
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 0.00294550
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 0.000242151
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 3.21426e-06
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 1.60211e-07
+DEAL:cg:cg::Convergence step 1 value 0.00000
+DEAL:cg:cg::Starting value 3.38024e-09
+DEAL:cg:cg::Convergence step 1 value 4.13590e-25
+DEAL:cg::Convergence step 6 value 2.56705e-07
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.cc b/tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.cc
new file mode 100644 (file)
index 0000000..b29a4c0
--- /dev/null
@@ -0,0 +1,498 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test running a multigrid solver on continuous FE_Q finite elements with
+// MatrixFree data structures with parallel::fullydistributd::Triangulation
+// (otherwise similar to tests/matrix_free/parallel_multigrid_mf.cc)
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/fully_distributed_tria.h>
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_description.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &                mapping,
+             const DoFHandler<dim> &             dof_handler,
+             const std::set<types::boundary_id> &dirichlet_boundaries,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.mg_level = level;
+
+    // extract the constraints due to Dirichlet boundary conditions
+    AffineConstraints<double>                           constraints;
+    Functions::ZeroFunction<dim>                        zero;
+    std::map<types::boundary_id, const Function<dim> *> functions;
+    for (std::set<types::boundary_id>::const_iterator it =
+           dirichlet_boundaries.begin();
+         it != dirichlet_boundaries.end();
+         ++it)
+      functions[*it] = &zero;
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, double> fine_matrix;
+  const std::set<types::boundary_id> dirichlet_boundaries = {0};
+  fine_matrix.initialize(mapping, dof, dirichlet_boundaries);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, dirichlet_boundaries, level);
+    }
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+
+  // temporarily disable deallog for the setup of the preconditioner that
+  // involves a CG solver for eigenvalue estimation
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim, int fe_degree, typename number>
+void
+test()
+{
+  for (unsigned int i = 5; i < 7; ++i)
+    {
+      dealii::Triangulation<dim> tria(
+        Triangulation<dim>::limit_level_difference_at_vertices);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      GridTools::partition_triangulation_zorder(
+        Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD), tria);
+      GridTools::partition_multigrid_levels(tria);
+
+
+      parallel::fullydistributed::Triangulation<dim> tria_pft(MPI_COMM_WORLD);
+
+      // extract relevant information form pdt
+      auto construction_data = TriangulationDescription::Utilities::
+        create_description_from_triangulation(
+          tria,
+          MPI_COMM_WORLD,
+          TriangulationDescription::Settings::construct_multigrid_hierarchy);
+
+      // actually create triangulation
+      tria_pft.create_triangulation(construction_data);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria_pft);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, number>(dof);
+    }
+
+  if (false)
+    for (unsigned int i = 5; i < 7; ++i)
+      {
+        parallel::distributed::Triangulation<dim> tria(
+          MPI_COMM_WORLD,
+          Triangulation<dim>::limit_level_difference_at_vertices,
+          parallel::distributed::Triangulation<
+            dim>::construct_multigrid_hierarchy);
+        GridGenerator::hyper_cube(tria);
+        tria.refine_global(i - dim);
+
+        parallel::fullydistributed::Triangulation<dim> tria_pft(MPI_COMM_WORLD);
+
+        // extract relevant information form pdt
+        auto construction_data = TriangulationDescription::Utilities::
+          create_description_from_triangulation(
+            tria,
+            MPI_COMM_WORLD,
+            TriangulationDescription::Settings::construct_multigrid_hierarchy);
+
+        // actually create triangulation
+        tria_pft.create_triangulation(construction_data);
+
+        FE_Q<dim>       fe(fe_degree);
+        DoFHandler<dim> dof(tria_pft);
+        dof.distribute_dofs(fe);
+        dof.distribute_mg_dofs();
+
+        do_test<dim, fe_degree, fe_degree + 1, number>(dof);
+      }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    test<2, 1, double>();
+    test<2, 2, float>();
+
+    test<3, 1, double>();
+    test<3, 2, float>();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.with_lapack=true.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_fullydistributed.with_lapack=true.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..cd88f52
--- /dev/null
@@ -0,0 +1,33 @@
+
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 81
+DEAL:cg::Starting value 9.00000
+DEAL:cg::Convergence step 3 value 6.75256e-07
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 2.62465e-09
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 1.71224e-08
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 1089
+DEAL:cg::Starting value 33.0000
+DEAL:cg::Convergence step 4 value 4.31534e-08
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 125
+DEAL:cg::Starting value 11.1803
+DEAL:cg::Convergence step 3 value 4.38307e-07
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 3 value 1.02520e-06
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 4 value 5.99244e-09
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 70.0928
+DEAL:cg::Convergence step 4 value 5.81100e-08
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_interleave.cc b/tests/multigrid-global-coarsening/parallel_multigrid_interleave.cc
new file mode 100644 (file)
index 0000000..bb3f5e7
--- /dev/null
@@ -0,0 +1,461 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Similar test as parallel_multigrid_mf, but using the functionality of
+// PreconditionChebyshev to embed vector updates into the matrix-free loops of
+// a suitable operator class.
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename number = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator()
+    : n_calls_vmult(0)
+  {}
+
+  void
+  print_n_calls_special()
+  {
+    // round number of calls to make test more robust
+    if (n_calls_vmult > 0)
+      deallog
+        << "Approx. number of calls to special vmult for Operator of size "
+        << m() << ": " << (n_calls_vmult + 5) / 10 * 10 << std::endl;
+  }
+
+  void
+  initialize(const Mapping<dim> &                mapping,
+             const DoFHandler<dim> &             dof_handler,
+             const std::set<types::boundary_id> &dirichlet_boundaries,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    n_calls_vmult = 0;
+    const QGauss<1> quad(dof_handler.get_fe().degree + 1);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.mg_level = level;
+
+    // extract the constraints due to Dirichlet boundary conditions
+    AffineConstraints<double>                           constraints;
+    Functions::ZeroFunction<dim>                        zero;
+    std::map<types::boundary_id, const Function<dim> *> functions;
+    for (std::set<types::boundary_id>::const_iterator it =
+           dirichlet_boundaries.begin();
+         it != dirichlet_boundaries.end();
+         ++it)
+      functions[*it] = &zero;
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src, true);
+    for (const unsigned int i : data.get_constrained_dofs())
+      dst.local_element(i) = src.local_element(i);
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src,
+        const std::function<void(const unsigned int, const unsigned int)>
+          &operation_before_loop,
+        const std::function<void(const unsigned int, const unsigned int)>
+          &operation_after_loop) const
+  {
+    ++n_calls_vmult;
+    data.cell_loop(&LaplaceOperator::local_apply,
+                   this,
+                   dst,
+                   src,
+                   operation_before_loop,
+                   operation_after_loop);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+    for (const unsigned int i : data.get_constrained_dofs())
+      dst.local_element(i) += src.local_element(i);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    AlignedVector<VectorizedArray<number>> local_diagonal_vector(
+      phi.dofs_per_cell);
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+  mutable unsigned int                       n_calls_vmult;
+};
+
+
+
+template <int dim, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  const unsigned int                 fe_degree = dof.get_fe().degree;
+  MappingQ<dim>                      mapping(fe_degree + 1);
+  LaplaceOperator<dim, double>       fine_matrix;
+  const std::set<types::boundary_id> dirichlet_boundaries = {0};
+  fine_matrix.initialize(mapping, dof, dirichlet_boundaries);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector, except boundary
+  in = 1.;
+  {
+    std::map<types::global_dof_index, double> boundary_values;
+    VectorTools::interpolate_boundary_values(dof,
+                                             0,
+                                             Functions::ZeroFunction<dim>(),
+                                             boundary_values);
+    for (const auto it : boundary_values)
+      if (dof.locally_owned_dofs().is_element(it.first))
+        in(it.first) = 0.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = LaplaceOperator<dim, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, dirichlet_boundaries, level);
+    }
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  mg::SmootherRelaxation<SMOOTHER, LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 4;
+      smoother_data[level].eig_cg_n_iterations = 10;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+
+  mg_smoother.initialize(mg_matrices, smoother_data);
+  MGCoarseGridApplySmoother<LinearAlgebra::distributed::Vector<number>>
+    mg_coarse(mg_smoother);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+
+    // Require a fixed number of iterations rather than a tolerance, in order
+    // to make output more stable
+    IterationNumberControl control(6, 1e-15);
+
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  // Print statistics
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].print_n_calls_special();
+
+  fine_matrix.print_n_calls_special();
+}
+
+
+
+template <int dim, typename number>
+void
+test(const unsigned int fe_degree)
+{
+  for (unsigned int i = 6; i < 8; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, number>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    test<2, double>(1);
+    test<2, float>(3);
+
+    test<3, double>(1);
+    test<3, float>(2);
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_interleave.with_p4est=true.with_lapack=true.mpirun=2.output b/tests/multigrid-global-coarsening/parallel_multigrid_interleave.with_p4est=true.with_lapack=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..f91c676
--- /dev/null
@@ -0,0 +1,73 @@
+
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 15.0000
+DEAL:cg::Convergence step 6 value 7.67890e-11
+DEAL::Approx. number of calls to special vmult for Operator of size 4: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 9: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 25: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 81: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 289: 50
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 1089
+DEAL:cg::Starting value 31.0000
+DEAL:cg::Convergence step 6 value 2.23750e-10
+DEAL::Approx. number of calls to special vmult for Operator of size 4: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 9: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 25: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 81: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 289: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 1089: 50
+DEAL::Testing FE_Q<2>(3)
+DEAL::Number of degrees of freedom: 2401
+DEAL:cg::Starting value 47.0000
+DEAL:cg::Convergence step 6 value 5.14228e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 16: 30
+DEAL::Approx. number of calls to special vmult for Operator of size 49: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 169: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 625: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 2401: 50
+DEAL::Testing FE_Q<2>(3)
+DEAL::Number of degrees of freedom: 9409
+DEAL:cg::Starting value 95.0000
+DEAL:cg::Convergence step 6 value 1.44454e-08
+DEAL::Approx. number of calls to special vmult for Operator of size 16: 30
+DEAL::Approx. number of calls to special vmult for Operator of size 49: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 169: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 625: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 2401: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 9409: 50
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 18.5203
+DEAL:cg::Convergence step 6 value 1.94706e-11
+DEAL::Approx. number of calls to special vmult for Operator of size 8: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 58.0948
+DEAL:cg::Convergence step 6 value 2.47598e-10
+DEAL::Approx. number of calls to special vmult for Operator of size 8: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 58.0948
+DEAL:cg::Convergence step 6 value 1.17825e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 35937
+DEAL:cg::Starting value 172.601
+DEAL:cg::Convergence step 6 value 4.79055e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 35937: 50
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.cc b/tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.cc
new file mode 100644 (file)
index 0000000..4bd129c
--- /dev/null
@@ -0,0 +1,502 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Similar test as parallel_multigrid_mf, but using the functionality of
+// PreconditionChebyshev to embed vector updates into the matrix-free loops of
+// a suitable operator class and with additional renumbering of unknowns
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_renumbering.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename number = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator()
+    : n_calls_vmult(0)
+  {}
+
+  void
+  print_n_calls_special()
+  {
+    // round number of calls to make test more robust
+    if (n_calls_vmult > 0)
+      deallog
+        << "Approx. number of calls to special vmult for Operator of size "
+        << m() << ": " << (n_calls_vmult + 5) / 10 * 10 << std::endl;
+  }
+
+  void
+  initialize(const Mapping<dim> &                mapping,
+             DoFHandler<dim> &                   dof_handler,
+             const std::set<types::boundary_id> &dirichlet_boundaries,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    n_calls_vmult = 0;
+    const QGauss<1> quad(dof_handler.get_fe().degree + 1);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.mg_level = level;
+
+    // extract the constraints due to Dirichlet boundary conditions
+    AffineConstraints<double>                           constraints;
+    Functions::ZeroFunction<dim>                        zero;
+    std::map<types::boundary_id, const Function<dim> *> functions;
+    for (std::set<types::boundary_id>::const_iterator it =
+           dirichlet_boundaries.begin();
+         it != dirichlet_boundaries.end();
+         ++it)
+      functions[*it] = &zero;
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    DoFRenumbering::matrix_free_data_locality(dof_handler,
+                                              constraints,
+                                              addit_data);
+
+    constraints.clear();
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src, true);
+    for (const unsigned int i : data.get_constrained_dofs())
+      dst.local_element(i) = src.local_element(i);
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src,
+        const std::function<void(const unsigned int, const unsigned int)>
+          &operation_before_loop,
+        const std::function<void(const unsigned int, const unsigned int)>
+          &operation_after_loop) const
+  {
+    ++n_calls_vmult;
+    data.cell_loop(&LaplaceOperator::local_apply,
+                   this,
+                   dst,
+                   src,
+                   operation_before_loop,
+                   operation_after_loop);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+    for (const unsigned int i : data.get_constrained_dofs())
+      dst.local_element(i) += src.local_element(i);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, -1, 0, 1, number> phi(data);
+
+    AlignedVector<VectorizedArray<number>> local_diagonal_vector(
+      phi.dofs_per_cell);
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+  mutable unsigned int                       n_calls_vmult;
+};
+
+
+
+template <int dim, typename number>
+void
+do_test(DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  const unsigned int                 fe_degree = dof.get_fe().degree;
+  MappingQ<dim>                      mapping(fe_degree + 1);
+  LaplaceOperator<dim, double>       fine_matrix;
+  const std::set<types::boundary_id> dirichlet_boundaries = {0};
+  fine_matrix.initialize(mapping, dof, dirichlet_boundaries);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector, except boundary
+  in = 1.;
+  {
+    std::map<types::global_dof_index, double> boundary_values;
+    VectorTools::interpolate_boundary_values(dof,
+                                             0,
+                                             Functions::ZeroFunction<dim>(),
+                                             boundary_values);
+    for (const auto it : boundary_values)
+      if (dof.locally_owned_dofs().is_element(it.first))
+        in(it.first) = 0.;
+  }
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType = LaplaceOperator<dim, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, dirichlet_boundaries, level);
+    }
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  mg::SmootherRelaxation<SMOOTHER, LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 4;
+      smoother_data[level].eig_cg_n_iterations = 10;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+
+  mg_smoother.initialize(mg_matrices, smoother_data);
+  MGCoarseGridApplySmoother<LinearAlgebra::distributed::Vector<number>>
+    mg_coarse(mg_smoother);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+
+    // Require a fixed number of iterations rather than a tolerance, in order
+    // to make output more stable
+    IterationNumberControl control(6, 1e-15);
+
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+
+  // Print statistics
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    mg_matrices[level].print_n_calls_special();
+
+  fine_matrix.print_n_calls_special();
+}
+
+
+
+template <int dim, typename number>
+void
+test(const unsigned int fe_degree)
+{
+  for (unsigned int i = 6; i < 8; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, number>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    test<2, double>(1);
+    test<2, float>(3);
+
+    test<3, double>(1);
+    test<3, float>(2);
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.with_p4est=true.with_lapack=true.mpirun=2.output b/tests/multigrid-global-coarsening/parallel_multigrid_interleave_renumber.with_p4est=true.with_lapack=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..9a4038f
--- /dev/null
@@ -0,0 +1,73 @@
+
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 15.0000
+DEAL:cg::Convergence step 6 value 5.63311e-11
+DEAL::Approx. number of calls to special vmult for Operator of size 4: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 9: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 25: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 81: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 289: 50
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 1089
+DEAL:cg::Starting value 31.0000
+DEAL:cg::Convergence step 6 value 6.08657e-10
+DEAL::Approx. number of calls to special vmult for Operator of size 4: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 9: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 25: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 81: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 289: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 1089: 50
+DEAL::Testing FE_Q<2>(3)
+DEAL::Number of degrees of freedom: 2401
+DEAL:cg::Starting value 47.0000
+DEAL:cg::Convergence step 6 value 2.11509e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 16: 30
+DEAL::Approx. number of calls to special vmult for Operator of size 49: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 169: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 625: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 2401: 50
+DEAL::Testing FE_Q<2>(3)
+DEAL::Number of degrees of freedom: 9409
+DEAL:cg::Starting value 95.0000
+DEAL:cg::Convergence step 6 value 8.72760e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 16: 30
+DEAL::Approx. number of calls to special vmult for Operator of size 49: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 169: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 625: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 2401: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 9409: 50
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 18.5203
+DEAL:cg::Convergence step 6 value 2.77603e-11
+DEAL::Approx. number of calls to special vmult for Operator of size 8: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 58.0948
+DEAL:cg::Convergence step 6 value 3.05980e-10
+DEAL::Approx. number of calls to special vmult for Operator of size 8: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 40
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 58.0948
+DEAL:cg::Convergence step 6 value 1.26786e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 35937
+DEAL:cg::Starting value 172.601
+DEAL:cg::Convergence step 6 value 4.72892e-09
+DEAL::Approx. number of calls to special vmult for Operator of size 27: 20
+DEAL::Approx. number of calls to special vmult for Operator of size 125: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 729: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 4913: 50
+DEAL::Approx. number of calls to special vmult for Operator of size 35937: 50
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_mf.cc b/tests/multigrid-global-coarsening/parallel_multigrid_mf.cc
new file mode 100644 (file)
index 0000000..5907c11
--- /dev/null
@@ -0,0 +1,448 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// same test as parallel_multigrid but using matrix-free transfer operations
+// (and including single-precision multigrid preconditioning)
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim,
+          int fe_degree,
+          int n_q_points_1d = fe_degree + 1,
+          typename number   = double>
+class LaplaceOperator : public Subscriptor
+{
+public:
+  using value_type = number;
+
+  LaplaceOperator(){};
+
+  void
+  initialize(const Mapping<dim> &                mapping,
+             const DoFHandler<dim> &             dof_handler,
+             const std::set<types::boundary_id> &dirichlet_boundaries,
+             const unsigned int level = numbers::invalid_unsigned_int)
+  {
+    const QGauss<1>                                  quad(n_q_points_1d);
+    typename MatrixFree<dim, number>::AdditionalData addit_data;
+    addit_data.tasks_parallel_scheme =
+      MatrixFree<dim, number>::AdditionalData::none;
+    addit_data.mg_level = level;
+
+    // extract the constraints due to Dirichlet boundary conditions
+    AffineConstraints<double>                           constraints;
+    Functions::ZeroFunction<dim>                        zero;
+    std::map<types::boundary_id, const Function<dim> *> functions;
+    for (std::set<types::boundary_id>::const_iterator it =
+           dirichlet_boundaries.begin();
+         it != dirichlet_boundaries.end();
+         ++it)
+      functions[*it] = &zero;
+    if (level == numbers::invalid_unsigned_int)
+      VectorTools::interpolate_boundary_values(dof_handler,
+                                               functions,
+                                               constraints);
+    else
+      {
+        std::vector<types::global_dof_index>    local_dofs;
+        typename DoFHandler<dim>::cell_iterator cell = dof_handler.begin(level),
+                                                endc = dof_handler.end(level);
+        for (; cell != endc; ++cell)
+          {
+            if (dof_handler.get_triangulation().locally_owned_subdomain() !=
+                  numbers::invalid_subdomain_id &&
+                cell->level_subdomain_id() == numbers::artificial_subdomain_id)
+              continue;
+            const FiniteElement<dim> &fe = cell->get_fe();
+            local_dofs.resize(fe.dofs_per_face);
+
+            for (const unsigned int face_no : GeometryInfo<dim>::face_indices())
+              if (cell->at_boundary(face_no) == true)
+                {
+                  const typename DoFHandler<dim>::face_iterator face =
+                    cell->face(face_no);
+                  const types::boundary_id bi = face->boundary_id();
+                  if (functions.find(bi) != functions.end())
+                    {
+                      face->get_mg_dof_indices(level, local_dofs);
+                      for (unsigned int i = 0; i < fe.dofs_per_face; ++i)
+                        constraints.add_line(local_dofs[i]);
+                    }
+                }
+          }
+      }
+    constraints.close();
+
+    data.reinit(mapping, dof_handler, constraints, quad, addit_data);
+
+    compute_inverse_diagonal();
+  }
+
+  void
+  vmult(LinearAlgebra::distributed::Vector<number> &      dst,
+        const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult(LinearAlgebra::distributed::Vector<number> &      dst,
+         const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    dst = 0;
+    vmult_add(dst, src);
+  }
+
+  void
+  Tvmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+             const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    vmult_add(dst, src);
+  }
+
+  void
+  vmult_add(LinearAlgebra::distributed::Vector<number> &      dst,
+            const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    data.cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+
+    const std::vector<unsigned int> &constrained_dofs =
+      data.get_constrained_dofs();
+    for (unsigned int i = 0; i < constrained_dofs.size(); ++i)
+      dst.local_element(constrained_dofs[i]) +=
+        src.local_element(constrained_dofs[i]);
+  }
+
+  types::global_dof_index
+  m() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  types::global_dof_index
+  n() const
+  {
+    return data.get_vector_partitioner()->size();
+  }
+
+  number
+  el(const unsigned int row, const unsigned int col) const
+  {
+    AssertThrow(false,
+                ExcMessage("Matrix-free does not allow for entry access"));
+    return number();
+  }
+
+  void
+  initialize_dof_vector(
+    LinearAlgebra::distributed::Vector<number> &vector) const
+  {
+    if (!vector.partitioners_are_compatible(
+          *data.get_dof_info(0).vector_partitioner))
+      data.initialize_dof_vector(vector);
+    Assert(vector.partitioners_are_globally_compatible(
+             *data.get_dof_info(0).vector_partitioner),
+           ExcInternalError());
+  }
+
+  const LinearAlgebra::distributed::Vector<number> &
+  get_matrix_diagonal_inverse() const
+  {
+    Assert(inverse_diagonal_entries.size() > 0, ExcNotInitialized());
+    return inverse_diagonal_entries;
+  }
+
+  const std::shared_ptr<const Utilities::MPI::Partitioner> &
+  get_vector_partitioner() const
+  {
+    return data.get_vector_partitioner();
+  }
+
+
+private:
+  void
+  local_apply(const MatrixFree<dim, number> &                   data,
+              LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src,
+              const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  void
+  compute_inverse_diagonal()
+  {
+    data.initialize_dof_vector(inverse_diagonal_entries);
+    unsigned int dummy = 0;
+    data.cell_loop(&LaplaceOperator::local_diagonal_cell,
+                   this,
+                   inverse_diagonal_entries,
+                   dummy);
+
+    for (unsigned int i = 0; i < inverse_diagonal_entries.locally_owned_size();
+         ++i)
+      if (std::abs(inverse_diagonal_entries.local_element(i)) > 1e-10)
+        inverse_diagonal_entries.local_element(i) =
+          1. / inverse_diagonal_entries.local_element(i);
+      else
+        inverse_diagonal_entries.local_element(i) = 1.;
+  }
+
+  void
+  local_diagonal_cell(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, n_q_points_1d, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        phi.reinit(cell);
+
+        VectorizedArray<number> local_diagonal_vector[phi.tensor_dofs_per_cell];
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.begin_dof_values()[j] = VectorizedArray<number>();
+            phi.begin_dof_values()[i] = 1.;
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(phi.get_gradient(q), q);
+            phi.integrate(EvaluationFlags::gradients);
+            local_diagonal_vector[i] = phi.begin_dof_values()[i];
+          }
+        for (unsigned int i = 0; i < phi.tensor_dofs_per_cell; ++i)
+          phi.begin_dof_values()[i] = local_diagonal_vector[i];
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+  MatrixFree<dim, number>                    data;
+  LinearAlgebra::distributed::Vector<number> inverse_diagonal_entries;
+};
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim>                                          mapping(fe_degree + 1);
+  LaplaceOperator<dim, fe_degree, n_q_points_1d, double> fine_matrix;
+  const std::set<types::boundary_id> dirichlet_boundaries = {0};
+  fine_matrix.initialize(mapping, dof, dirichlet_boundaries);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  using LevelMatrixType =
+    LaplaceOperator<dim, fe_degree, n_q_points_1d, number>;
+
+  MGLevelObject<LevelMatrixType> mg_matrices;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      mg_matrices[level].initialize(mapping, dof, dirichlet_boundaries, level);
+    }
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners;
+  for (unsigned int level = mg_matrices.min_level();
+       level <= mg_matrices.max_level();
+       ++level)
+    partitioners.push_back(mg_matrices[level].get_vector_partitioner());
+
+  MGTransferMF<dim, number> mg_transfer(mg_constrained_dofs);
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      auto preconditioner                      = std::make_shared<
+        DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>>();
+      preconditioner->reinit(mg_matrices[level].get_matrix_diagonal_inverse());
+      smoother_data[level].preconditioner = std::move(preconditioner);
+    }
+
+  // temporarily disable deallog for the setup of the preconditioner that
+  // involves a CG solver for eigenvalue estimation
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim, int fe_degree, typename number>
+void
+test()
+{
+  for (unsigned int i = 5; i < 7; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, number>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    test<2, 1, double>();
+    test<2, 2, float>();
+
+    test<3, 1, double>();
+    test<3, 2, float>();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_mf.with_p4est=true.with_lapack=true.mpirun=7.output b/tests/multigrid-global-coarsening/parallel_multigrid_mf.with_p4est=true.with_lapack=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..cd88f52
--- /dev/null
@@ -0,0 +1,33 @@
+
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 81
+DEAL:cg::Starting value 9.00000
+DEAL:cg::Convergence step 3 value 6.75256e-07
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 2.62465e-09
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 1.71224e-08
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 1089
+DEAL:cg::Starting value 33.0000
+DEAL:cg::Convergence step 4 value 4.31534e-08
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 125
+DEAL:cg::Starting value 11.1803
+DEAL:cg::Convergence step 3 value 4.38307e-07
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 3 value 1.02520e-06
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 4 value 5.99244e-09
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 70.0928
+DEAL:cg::Convergence step 4 value 5.81100e-08
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_mf_02.cc b/tests/multigrid-global-coarsening/parallel_multigrid_mf_02.cc
new file mode 100644 (file)
index 0000000..6eea7ca
--- /dev/null
@@ -0,0 +1,277 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2014 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// same test as parallel_multigrid_mf but using the Laplace operator from
+// MatrixFreeOperators::Laplace and handing the vector partitioning of those
+// operators to the MG transfer
+
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_handler.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/mapping_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+
+template <typename MatrixType, typename Number>
+class MGCoarseIterative
+  : public MGCoarseGridBase<LinearAlgebra::distributed::Vector<Number>>
+{
+public:
+  MGCoarseIterative()
+  {}
+
+  void
+  initialize(const MatrixType &matrix)
+  {
+    coarse_matrix = &matrix;
+  }
+
+  virtual void
+  operator()(const unsigned int                                level,
+             LinearAlgebra::distributed::Vector<Number> &      dst,
+             const LinearAlgebra::distributed::Vector<Number> &src) const
+  {
+    ReductionControl solver_control(1e4, 1e-50, 1e-10);
+    SolverCG<LinearAlgebra::distributed::Vector<Number>> solver_coarse(
+      solver_control);
+    solver_coarse.solve(*coarse_matrix, dst, src, PreconditionIdentity());
+  }
+
+  const MatrixType *coarse_matrix;
+};
+
+
+
+template <int dim, int fe_degree, int n_q_points_1d, typename number>
+void
+do_test(const DoFHandler<dim> &dof)
+{
+  deallog << "Testing " << dof.get_fe().get_name();
+  deallog << std::endl;
+  deallog << "Number of degrees of freedom: " << dof.n_dofs() << std::endl;
+
+  MappingQ<dim> mapping(fe_degree + 1);
+  MatrixFreeOperators::LaplaceOperator<
+    dim,
+    fe_degree,
+    n_q_points_1d,
+    1,
+    LinearAlgebra::distributed::Vector<double>>
+    fine_matrix;
+
+  // Dirichlet BC
+  Functions::ZeroFunction<dim>                        zero_function;
+  std::map<types::boundary_id, const Function<dim> *> dirichlet_boundary;
+  dirichlet_boundary[0] = &zero_function;
+
+  // fine-level constraints
+  IndexSet locally_relevant_dofs;
+  DoFTools::extract_locally_relevant_dofs(dof, locally_relevant_dofs);
+  AffineConstraints<double> constraints;
+  constraints.reinit(locally_relevant_dofs);
+  VectorTools::interpolate_boundary_values(dof,
+                                           dirichlet_boundary,
+                                           constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim, double>> fine_level_data(
+    new MatrixFree<dim, double>());
+
+  typename MatrixFree<dim, double>::AdditionalData fine_level_additional_data;
+  fine_level_data->reinit(mapping,
+                          dof,
+                          constraints,
+                          QGauss<1>(n_q_points_1d),
+                          fine_level_additional_data);
+
+  fine_matrix.initialize(fine_level_data);
+
+  LinearAlgebra::distributed::Vector<double> in, sol;
+  fine_matrix.initialize_dof_vector(in);
+  fine_matrix.initialize_dof_vector(sol);
+
+  // set constant rhs vector
+  in = 1.;
+
+  // set up multigrid in analogy to step-37
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(dof);
+  mg_constrained_dofs.make_zero_boundary_constraints(dof, {0});
+
+  using LevelMatrixType = MatrixFreeOperators::LaplaceOperator<
+    dim,
+    fe_degree,
+    n_q_points_1d,
+    1,
+    LinearAlgebra::distributed::Vector<number>>;
+
+  MGLevelObject<LevelMatrixType>                          mg_matrices;
+  MGLevelObject<std::shared_ptr<MatrixFree<dim, number>>> mg_level_data;
+  mg_matrices.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  mg_level_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      typename MatrixFree<dim, number>::AdditionalData mg_additional_data;
+      mg_additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, number>::AdditionalData::none;
+      mg_additional_data.tasks_block_size = 3;
+      mg_additional_data.mg_level         = level;
+
+      AffineConstraints<double> level_constraints;
+      IndexSet                  relevant_dofs;
+      DoFTools::extract_locally_relevant_level_dofs(dof, level, relevant_dofs);
+      level_constraints.reinit(relevant_dofs);
+      level_constraints.add_lines(
+        mg_constrained_dofs.get_boundary_indices(level));
+      level_constraints.close();
+
+      mg_level_data[level].reset(new MatrixFree<dim, number>());
+      mg_level_data[level]->reinit(mapping,
+                                   dof,
+                                   level_constraints,
+                                   QGauss<1>(n_q_points_1d),
+                                   mg_additional_data);
+      mg_matrices[level].initialize(mg_level_data[level],
+                                    mg_constrained_dofs,
+                                    level);
+      mg_matrices[level].compute_diagonal();
+    }
+
+  MGTransferMF<dim, number>                                       mg_transfer;
+  std::vector<std::shared_ptr<const Utilities::MPI::Partitioner>> partitioners(
+    dof.get_triangulation().n_global_levels());
+  for (unsigned int level = 0; level < partitioners.size(); ++level)
+    partitioners[level] =
+      mg_level_data[level]->get_dof_info().vector_partitioner;
+  mg_transfer.build(dof, partitioners);
+
+  MGCoarseIterative<LevelMatrixType, number> mg_coarse;
+  mg_coarse.initialize(mg_matrices[0]);
+
+  using SMOOTHER =
+    PreconditionChebyshev<LevelMatrixType,
+                          LinearAlgebra::distributed::Vector<number>>;
+  MGSmootherPrecondition<LevelMatrixType,
+                         SMOOTHER,
+                         LinearAlgebra::distributed::Vector<number>>
+    mg_smoother;
+
+  MGLevelObject<typename SMOOTHER::AdditionalData> smoother_data;
+  smoother_data.resize(0, dof.get_triangulation().n_global_levels() - 1);
+  for (unsigned int level = 0;
+       level < dof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      smoother_data[level].smoothing_range     = 15.;
+      smoother_data[level].degree              = 5;
+      smoother_data[level].eig_cg_n_iterations = 15;
+      smoother_data[level].preconditioner =
+        mg_matrices[level].get_matrix_diagonal_inverse();
+    }
+
+  // temporarily disable deallog for the setup of the preconditioner that
+  // involves a CG solver for eigenvalue estimation
+  mg_smoother.initialize(mg_matrices, smoother_data);
+
+  mg::Matrix<LinearAlgebra::distributed::Vector<number>> mg_matrix(mg_matrices);
+
+  Multigrid<LinearAlgebra::distributed::Vector<number>> mg(
+    mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+  PreconditionMG<dim,
+                 LinearAlgebra::distributed::Vector<number>,
+                 MGTransferMF<dim, number>>
+    preconditioner(dof, mg, mg_transfer);
+
+  {
+    // avoid output from inner (coarse-level) solver
+    deallog.depth_file(2);
+    ReductionControl control(30, 1e-20, 1e-7);
+    SolverCG<LinearAlgebra::distributed::Vector<double>> solver(control);
+    solver.solve(fine_matrix, sol, in, preconditioner);
+  }
+}
+
+
+
+template <int dim, int fe_degree, typename number>
+void
+test()
+{
+  for (unsigned int i = 5; i < 7; ++i)
+    {
+      parallel::distributed::Triangulation<dim> tria(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::hyper_cube(tria);
+      tria.refine_global(i - dim);
+
+      FE_Q<dim>       fe(fe_degree);
+      DoFHandler<dim> dof(tria);
+      dof.distribute_dofs(fe);
+      dof.distribute_mg_dofs();
+
+      do_test<dim, fe_degree, fe_degree + 1, number>(dof);
+    }
+}
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+
+  mpi_initlog();
+
+  {
+    test<2, 1, double>();
+    test<2, 2, float>();
+
+    test<3, 1, double>();
+    test<3, 2, float>();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/parallel_multigrid_mf_02.with_p4est=true.with_lapack=true.mpirun=3.output b/tests/multigrid-global-coarsening/parallel_multigrid_mf_02.with_p4est=true.with_lapack=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..604fbf3
--- /dev/null
@@ -0,0 +1,33 @@
+
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 81
+DEAL:cg::Starting value 9.00000
+DEAL:cg::Convergence step 4 value 2.07070e-08
+DEAL::Testing FE_Q<2>(1)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 2.77789e-08
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 289
+DEAL:cg::Starting value 17.0000
+DEAL:cg::Convergence step 4 value 3.93059e-08
+DEAL::Testing FE_Q<2>(2)
+DEAL::Number of degrees of freedom: 1089
+DEAL:cg::Starting value 33.0000
+DEAL:cg::Convergence step 4 value 8.11904e-08
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 125
+DEAL:cg::Starting value 11.1803
+DEAL:cg::Convergence step 4 value 3.45976e-07
+DEAL::Testing FE_Q<3>(1)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 4 value 1.07425e-07
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 729
+DEAL:cg::Starting value 27.0000
+DEAL:cg::Convergence step 4 value 2.46943e-06
+DEAL::Testing FE_Q<3>(2)
+DEAL::Number of degrees of freedom: 4913
+DEAL:cg::Starting value 70.0928
+DEAL:cg::Convergence step 4 value 4.57526e-06
diff --git a/tests/multigrid-global-coarsening/step-37-inhomogeneous-1.cc b/tests/multigrid-global-coarsening/step-37-inhomogeneous-1.cc
new file mode 100644 (file)
index 0000000..6aaf0cc
--- /dev/null
@@ -0,0 +1,656 @@
+/* ---------------------------------------------------------------------
+ *
+ * Copyright (C) 2009 - 2022 by the deal.II authors
+ *
+ * This file is part of the deal.II library.
+ *
+ * The deal.II library is free software; you can use it, redistribute
+ * it, and/or modify it under the terms of the GNU Lesser General
+ * Public License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * The full text of the license can be found in the file LICENSE.md at
+ * the top level directory of deal.II.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Authors: Katharina Kormann, Martin Kronbichler, Uppsala University,
+ * 2009-2012, updated to MPI version with parallel vectors in 2016
+ */
+
+// This test verifies that the first strategy for enforcing inhomogeneous
+// boundary conditions (i.e., using read_dof_values_plain to compute the
+// contribution of the constraints to the right hand side in assemble_rhs)
+// given in step-37 works.
+
+
+#include <deal.II/base/conditional_ostream.h>
+#include <deal.II/base/function.h>
+#include <deal.II/base/quadrature_lib.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/la_parallel_vector.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/data_out.h>
+#include <deal.II/numerics/vector_tools.h>
+
+#include <fstream>
+#include <iostream>
+
+#include "../tests.h"
+
+namespace Step37
+{
+  const unsigned int degree_finite_element = 2;
+
+  template <int dim>
+  class ManufacturedSolution : public Function<dim>
+  {
+  public:
+    virtual double
+    value(const Point<dim> &p,
+          const unsigned int /*component*/ = 0) const override
+    {
+      const double pi = numbers::PI;
+      return std::sin(pi * p[0]) + std::cos(pi * p[1]);
+    }
+  };
+
+
+
+  template <int dim>
+  class ManufacturedForcing : public Function<dim>
+  {
+  public:
+    virtual double
+    value(const Point<dim> &p,
+          const unsigned int /*compononent*/ = 0) const override
+    {
+      return value<double>(p);
+    }
+
+    template <typename number>
+    number
+    value(const Point<dim, number> &p) const
+    {
+      const double pi = numbers::PI;
+      const number d  = 40.0 * p.square() + 1.0;
+      return 20 * pi * pi * std::cos(pi * p[1]) / d +
+             20 * pi * pi * std::sin(pi * p[0]) / d +
+             1600 * pi * p[0] * std::cos(pi * p[0]) / (d * d) -
+             1600 * pi * p[1] * std::sin(pi * p[1]) / (d * d);
+    }
+  };
+
+
+  template <int dim>
+  class Coefficient : public Function<dim>
+  {
+  public:
+    Coefficient()
+      : Function<dim>()
+    {}
+
+    virtual double
+    value(const Point<dim> &p, const unsigned int component = 0) const override;
+
+    template <typename number>
+    number
+    value(const Point<dim, number> &p, const unsigned int component = 0) const;
+  };
+
+
+
+  template <int dim>
+  template <typename number>
+  number
+  Coefficient<dim>::value(const Point<dim, number> &p,
+                          const unsigned int /*component*/) const
+  {
+    return 1. / (0.05 + 2. * p.square());
+  }
+
+
+
+  template <int dim>
+  double
+  Coefficient<dim>::value(const Point<dim> & p,
+                          const unsigned int component) const
+  {
+    return value<double>(p, component);
+  }
+
+
+  template <int dim, int fe_degree, typename number>
+  class LaplaceOperator
+    : public MatrixFreeOperators::
+        Base<dim, LinearAlgebra::distributed::Vector<number>>
+  {
+  public:
+    using value_type = number;
+
+    LaplaceOperator();
+
+    void
+    clear() override;
+
+    void
+    evaluate_coefficient(const Coefficient<dim> &coefficient_function);
+
+    virtual void
+    compute_diagonal() override;
+
+    const Table<2, VectorizedArray<double>> &
+    get_coefficient() const
+    {
+      return coefficient;
+    }
+
+  private:
+    virtual void
+    apply_add(
+      LinearAlgebra::distributed::Vector<number> &      dst,
+      const LinearAlgebra::distributed::Vector<number> &src) const override;
+
+    void
+    local_apply(const MatrixFree<dim, number> &                   data,
+                LinearAlgebra::distributed::Vector<number> &      dst,
+                const LinearAlgebra::distributed::Vector<number> &src,
+                const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    void
+    local_compute_diagonal(
+      const MatrixFree<dim, number> &              data,
+      LinearAlgebra::distributed::Vector<number> & dst,
+      const unsigned int &                         dummy,
+      const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    Table<2, VectorizedArray<number>> coefficient;
+  };
+
+
+
+  template <int dim, int fe_degree, typename number>
+  LaplaceOperator<dim, fe_degree, number>::LaplaceOperator()
+    : MatrixFreeOperators::Base<dim,
+                                LinearAlgebra::distributed::Vector<number>>()
+  {}
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::clear()
+  {
+    coefficient.reinit(0, 0);
+    MatrixFreeOperators::Base<dim, LinearAlgebra::distributed::Vector<number>>::
+      clear();
+  }
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::evaluate_coefficient(
+    const Coefficient<dim> &coefficient_function)
+  {
+    const unsigned int n_cells = this->data->n_cell_batches();
+    FEEvaluation<dim, fe_degree, fe_degree + 1, 1, number> phi(*this->data);
+
+    coefficient.reinit(n_cells, phi.n_q_points);
+    for (unsigned int cell = 0; cell < n_cells; ++cell)
+      {
+        phi.reinit(cell);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          coefficient(cell, q) =
+            coefficient_function.value(phi.quadrature_point(q));
+      }
+  }
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::local_apply(
+    const MatrixFree<dim, number> &                   data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, fe_degree + 1, 1, number> phi(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        AssertDimension(coefficient.size(0), data.n_cell_batches());
+        AssertDimension(coefficient.size(1), phi.n_q_points);
+
+        phi.reinit(cell);
+        phi.read_dof_values(src);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          phi.submit_gradient(coefficient(cell, q) * phi.get_gradient(q), q);
+        phi.integrate(EvaluationFlags::gradients);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::apply_add(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    this->data->cell_loop(&LaplaceOperator::local_apply, this, dst, src);
+  }
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::compute_diagonal()
+  {
+    this->inverse_diagonal_entries.reset(
+      new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+    LinearAlgebra::distributed::Vector<number> &inverse_diagonal =
+      this->inverse_diagonal_entries->get_vector();
+    this->data->initialize_dof_vector(inverse_diagonal);
+    unsigned int dummy = 0;
+    this->data->cell_loop(&LaplaceOperator::local_compute_diagonal,
+                          this,
+                          inverse_diagonal,
+                          dummy);
+
+    this->set_constrained_entries_to_one(inverse_diagonal);
+
+    for (unsigned int i = 0; i < inverse_diagonal.locally_owned_size(); ++i)
+      {
+        Assert(inverse_diagonal.local_element(i) > 0.,
+               ExcMessage("No diagonal entry in a positive definite operator "
+                          "should be zero"));
+        inverse_diagonal.local_element(i) =
+          1. / inverse_diagonal.local_element(i);
+      }
+  }
+
+
+
+  template <int dim, int fe_degree, typename number>
+  void
+  LaplaceOperator<dim, fe_degree, number>::local_compute_diagonal(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, fe_degree, fe_degree + 1, 1, number> phi(data);
+
+    AlignedVector<VectorizedArray<number>> diagonal(phi.dofs_per_cell);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        AssertDimension(coefficient.size(0), data.n_cell_batches());
+        AssertDimension(coefficient.size(1), phi.n_q_points);
+
+        phi.reinit(cell);
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < phi.dofs_per_cell; ++j)
+              phi.submit_dof_value(VectorizedArray<number>(), j);
+            phi.submit_dof_value(make_vectorized_array<number>(1.), i);
+
+            phi.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < phi.n_q_points; ++q)
+              phi.submit_gradient(coefficient(cell, q) * phi.get_gradient(q),
+                                  q);
+            phi.integrate(EvaluationFlags::gradients);
+            diagonal[i] = phi.get_dof_value(i);
+          }
+        for (unsigned int i = 0; i < phi.dofs_per_cell; ++i)
+          phi.submit_dof_value(diagonal[i], i);
+        phi.distribute_local_to_global(dst);
+      }
+  }
+
+
+
+  template <int dim>
+  class LaplaceProblem
+  {
+  public:
+    LaplaceProblem();
+    void
+    run();
+
+  private:
+    void
+    setup_system();
+    void
+    assemble_rhs();
+    void
+    solve();
+    void
+    output_results(const unsigned int cycle) const;
+
+    parallel::distributed::Triangulation<dim> triangulation;
+
+    FE_Q<dim>       fe;
+    DoFHandler<dim> dof_handler;
+
+    AffineConstraints<double> constraints;
+    using SystemMatrixType =
+      LaplaceOperator<dim, degree_finite_element, double>;
+    SystemMatrixType system_matrix;
+
+    MGConstrainedDoFs mg_constrained_dofs;
+    using LevelMatrixType = LaplaceOperator<dim, degree_finite_element, float>;
+    MGLevelObject<LevelMatrixType> mg_matrices;
+
+    LinearAlgebra::distributed::Vector<double> solution;
+    LinearAlgebra::distributed::Vector<double> system_rhs;
+
+    ConditionalOStream pcout;
+  };
+
+
+
+  template <int dim>
+  LaplaceProblem<dim>::LaplaceProblem()
+    : triangulation(MPI_COMM_WORLD,
+                    Triangulation<dim>::limit_level_difference_at_vertices,
+                    parallel::distributed::Triangulation<
+                      dim>::construct_multigrid_hierarchy)
+    , fe(degree_finite_element)
+    , dof_handler(triangulation)
+    , pcout(deallog.get_file_stream(),
+            Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
+  {}
+
+
+
+  template <int dim>
+  void
+  LaplaceProblem<dim>::setup_system()
+  {
+    system_matrix.clear();
+    mg_matrices.clear_elements();
+
+    dof_handler.distribute_dofs(fe);
+    dof_handler.distribute_mg_dofs();
+
+    pcout << "Number of degrees of freedom: " << dof_handler.n_dofs()
+          << std::endl;
+
+    IndexSet locally_relevant_dofs;
+    DoFTools::extract_locally_relevant_dofs(dof_handler, locally_relevant_dofs);
+
+    constraints.clear();
+    constraints.reinit(locally_relevant_dofs);
+    DoFTools::make_hanging_node_constraints(dof_handler, constraints);
+    VectorTools::interpolate_boundary_values(dof_handler,
+                                             0,
+                                             ManufacturedSolution<dim>(),
+                                             constraints);
+    constraints.close();
+
+    {
+      typename MatrixFree<dim, double>::AdditionalData additional_data;
+      additional_data.tasks_parallel_scheme =
+        MatrixFree<dim, double>::AdditionalData::none;
+      additional_data.mapping_update_flags =
+        (update_gradients | update_JxW_values | update_quadrature_points);
+      std::shared_ptr<MatrixFree<dim, double>> system_mf_storage(
+        new MatrixFree<dim, double>());
+      system_mf_storage->reinit(MappingQ1<dim>{},
+                                dof_handler,
+                                constraints,
+                                QGauss<1>(fe.degree + 1),
+                                additional_data);
+      system_matrix.initialize(system_mf_storage);
+    }
+
+    system_matrix.evaluate_coefficient(Coefficient<dim>());
+
+    system_matrix.initialize_dof_vector(solution);
+    system_matrix.initialize_dof_vector(system_rhs);
+
+    const unsigned int nlevels = triangulation.n_global_levels();
+    mg_matrices.resize(0, nlevels - 1);
+
+    const std::set<types::boundary_id> dirichlet_boundary = {0};
+    mg_constrained_dofs.initialize(dof_handler);
+    mg_constrained_dofs.make_zero_boundary_constraints(dof_handler,
+                                                       dirichlet_boundary);
+
+    for (unsigned int level = 0; level < nlevels; ++level)
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_level_dofs(dof_handler,
+                                                      level,
+                                                      relevant_dofs);
+        AffineConstraints<double> level_constraints;
+        level_constraints.reinit(relevant_dofs);
+        level_constraints.add_lines(
+          mg_constrained_dofs.get_boundary_indices(level));
+        level_constraints.close();
+
+        typename MatrixFree<dim, float>::AdditionalData additional_data;
+        additional_data.tasks_parallel_scheme =
+          MatrixFree<dim, float>::AdditionalData::none;
+        additional_data.mapping_update_flags =
+          (update_gradients | update_JxW_values | update_quadrature_points);
+        additional_data.mg_level = level;
+        std::shared_ptr<MatrixFree<dim, float>> mg_mf_storage_level(
+          new MatrixFree<dim, float>());
+        mg_mf_storage_level->reinit(MappingQ1<dim>{},
+                                    dof_handler,
+                                    level_constraints,
+                                    QGauss<1>(fe.degree + 1),
+                                    additional_data);
+
+        mg_matrices[level].initialize(mg_mf_storage_level,
+                                      mg_constrained_dofs,
+                                      level);
+        mg_matrices[level].evaluate_coefficient(Coefficient<dim>());
+      }
+  }
+
+
+
+  template <int dim>
+  void
+  LaplaceProblem<dim>::assemble_rhs()
+  {
+    solution = 0.0;
+    constraints.distribute(solution);
+    solution.update_ghost_values();
+    system_rhs = 0.0;
+
+    const Table<2, VectorizedArray<double>> &coefficient =
+      system_matrix.get_coefficient();
+    ManufacturedForcing<dim> forcing;
+
+    FEEvaluation<dim, degree_finite_element> phi(
+      *system_matrix.get_matrix_free());
+    for (unsigned int cell = 0;
+         cell < system_matrix.get_matrix_free()->n_cell_batches();
+         ++cell)
+      {
+        phi.reinit(cell);
+        phi.read_dof_values_plain(solution);
+        phi.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < phi.n_q_points; ++q)
+          {
+            phi.submit_gradient(-coefficient(cell, q) * phi.get_gradient(q), q);
+            phi.submit_value(forcing.value(phi.quadrature_point(q)), q);
+          }
+        phi.integrate(EvaluationFlags::values | EvaluationFlags::gradients);
+        phi.distribute_local_to_global(system_rhs);
+      }
+    system_rhs.compress(VectorOperation::add);
+  }
+
+
+
+  template <int dim>
+  void
+  LaplaceProblem<dim>::solve()
+  {
+    MGTransferMF<dim, float> mg_transfer(mg_constrained_dofs);
+    mg_transfer.build(dof_handler);
+
+    using SmootherType =
+      PreconditionChebyshev<LevelMatrixType,
+                            LinearAlgebra::distributed::Vector<float>>;
+    mg::SmootherRelaxation<SmootherType,
+                           LinearAlgebra::distributed::Vector<float>>
+                                                         mg_smoother;
+    MGLevelObject<typename SmootherType::AdditionalData> smoother_data;
+    smoother_data.resize(0, triangulation.n_global_levels() - 1);
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      {
+        if (level > 0)
+          {
+            smoother_data[level].smoothing_range     = 15.;
+            smoother_data[level].degree              = 4;
+            smoother_data[level].eig_cg_n_iterations = 10;
+          }
+        else
+          {
+            smoother_data[0].smoothing_range = 1e-3;
+            smoother_data[0].degree          = numbers::invalid_unsigned_int;
+            smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m();
+          }
+        mg_matrices[level].compute_diagonal();
+        smoother_data[level].preconditioner =
+          mg_matrices[level].get_matrix_diagonal_inverse();
+      }
+    mg_smoother.initialize(mg_matrices, smoother_data);
+
+    MGCoarseGridApplySmoother<LinearAlgebra::distributed::Vector<float>>
+      mg_coarse;
+    mg_coarse.initialize(mg_smoother);
+
+    mg::Matrix<LinearAlgebra::distributed::Vector<float>> mg_matrix(
+      mg_matrices);
+
+    MGLevelObject<MatrixFreeOperators::MGInterfaceOperator<LevelMatrixType>>
+      mg_interface_matrices;
+    mg_interface_matrices.resize(0, triangulation.n_global_levels() - 1);
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      mg_interface_matrices[level].initialize(mg_matrices[level]);
+    mg::Matrix<LinearAlgebra::distributed::Vector<float>> mg_interface(
+      mg_interface_matrices);
+
+    Multigrid<LinearAlgebra::distributed::Vector<float>> mg(
+      mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother);
+    mg.set_edge_matrices(mg_interface, mg_interface);
+
+    PreconditionMG<dim,
+                   LinearAlgebra::distributed::Vector<float>,
+                   MGTransferMF<dim, float>>
+      preconditioner(dof_handler, mg, mg_transfer);
+
+    SolverControl solver_control(100, 1e-12 * system_rhs.l2_norm());
+    SolverCG<LinearAlgebra::distributed::Vector<double>> cg(solver_control);
+
+    constraints.set_zero(solution);
+    cg.solve(system_matrix, solution, system_rhs, preconditioner);
+
+    constraints.distribute(solution);
+  }
+
+
+
+  template <int dim>
+  void
+  LaplaceProblem<dim>::output_results(const unsigned int cycle) const
+  {
+    if (triangulation.n_global_active_cells() > 1000000)
+      return;
+
+    Vector<double> errors;
+    errors.reinit(triangulation.n_active_cells());
+    solution.update_ghost_values();
+    VectorTools::integrate_difference(dof_handler,
+                                      solution,
+                                      ManufacturedSolution<dim>(),
+                                      errors,
+                                      QIterated<dim>(QTrapezoid<1>(), 4),
+                                      VectorTools::NormType::Linfty_norm);
+    double max_cell_error = 1.0;
+    if (errors.begin() != errors.end())
+      max_cell_error = *std::max_element(errors.begin(), errors.end());
+    max_cell_error = Utilities::MPI::max(max_cell_error, MPI_COMM_WORLD);
+    Assert(max_cell_error != 0.0, ExcInternalError());
+    pcout << "max error: " << max_cell_error << '\n';
+    static double error = max_cell_error;
+    pcout << "error ratio: "
+          << Utilities::MPI::max(error, MPI_COMM_WORLD) / max_cell_error
+          << '\n';
+    error = max_cell_error;
+  }
+
+
+
+  template <int dim>
+  void
+  LaplaceProblem<dim>::run()
+  {
+    for (unsigned int cycle = 0; cycle < 8 - dim; ++cycle)
+      {
+        pcout << "Cycle " << cycle << std::endl;
+
+        if (cycle == 0)
+          {
+            GridGenerator::hyper_cube(triangulation, 0., 1.);
+            triangulation.refine_global(3 - dim);
+          }
+        triangulation.refine_global(1);
+        setup_system();
+        assemble_rhs();
+        solve();
+        output_results(cycle);
+        pcout << std::endl;
+      }
+  }
+} // namespace Step37
+
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv, 1);
+  MPILogInitAll                    mpi_log;
+
+  {
+    Step37::LaplaceProblem<2> laplace_problem;
+    laplace_problem.run();
+  }
+
+  {
+    Step37::LaplaceProblem<3> laplace_problem;
+    laplace_problem.run();
+  }
+}
diff --git a/tests/multigrid-global-coarsening/step-37-inhomogeneous-1.with_lapack=true.mpirun=4.with_p4est=true.output b/tests/multigrid-global-coarsening/step-37-inhomogeneous-1.with_lapack=true.mpirun=4.with_p4est=true.output
new file mode 100644 (file)
index 0000000..59dbf7d
--- /dev/null
@@ -0,0 +1,150 @@
+
+Cycle 0
+Number of degrees of freedom: 81
+DEAL:0:cg::Starting value 45.0807
+DEAL:0:cg::Convergence step 7 value 2.65304e-12
+max error: 0.00772526
+error ratio: 1.00000
+
+Cycle 1
+Number of degrees of freedom: 289
+DEAL:0:cg::Starting value 68.5863
+DEAL:0:cg::Convergence step 7 value 3.81082e-12
+max error: 0.000971239
+error ratio: 7.95402
+
+Cycle 2
+Number of degrees of freedom: 1089
+DEAL:0:cg::Starting value 95.4381
+DEAL:0:cg::Convergence step 7 value 7.14371e-12
+max error: 0.000120278
+error ratio: 8.07497
+
+Cycle 3
+Number of degrees of freedom: 4225
+DEAL:0:cg::Starting value 131.732
+DEAL:0:cg::Convergence step 7 value 1.44204e-11
+max error: 1.49228e-05
+error ratio: 8.05998
+
+Cycle 4
+Number of degrees of freedom: 16641
+DEAL:0:cg::Starting value 183.473
+DEAL:0:cg::Convergence step 7 value 2.54095e-11
+max error: 1.85713e-06
+error ratio: 8.03544
+
+Cycle 5
+Number of degrees of freedom: 66049
+DEAL:0:cg::Starting value 257.379
+DEAL:0:cg::Convergence step 7 value 3.94318e-11
+max error: 2.31590e-07
+error ratio: 8.01904
+
+Cycle 0
+Number of degrees of freedom: 125
+DEAL:0:cg::Starting value 6.44073
+DEAL:0:cg::Convergence step 7 value 4.64523e-13
+max error: 0.0499110
+error ratio: 1.00000
+
+Cycle 1
+Number of degrees of freedom: 729
+DEAL:0:cg::Starting value 8.68642
+DEAL:0:cg::Convergence step 7 value 5.79753e-13
+max error: 0.00756448
+error ratio: 6.59807
+
+Cycle 2
+Number of degrees of freedom: 4913
+DEAL:0:cg::Starting value 9.47362
+DEAL:0:cg::Convergence step 7 value 6.67651e-13
+max error: 0.000965192
+error ratio: 7.83728
+
+Cycle 3
+Number of degrees of freedom: 35937
+DEAL:0:cg::Starting value 9.30402
+DEAL:0:cg::Convergence step 7 value 9.36336e-13
+max error: 0.000120048
+error ratio: 8.04008
+
+Cycle 4
+Number of degrees of freedom: 274625
+DEAL:0:cg::Starting value 8.99023
+DEAL:0:cg::Convergence step 7 value 1.22268e-12
+max error: 1.49140e-05
+error ratio: 8.04933
+
+
+DEAL:1:cg::Starting value 45.0807
+DEAL:1:cg::Convergence step 7 value 2.65304e-12
+DEAL:1:cg::Starting value 68.5863
+DEAL:1:cg::Convergence step 7 value 3.81082e-12
+DEAL:1:cg::Starting value 95.4381
+DEAL:1:cg::Convergence step 7 value 7.14371e-12
+DEAL:1:cg::Starting value 131.732
+DEAL:1:cg::Convergence step 7 value 1.44204e-11
+DEAL:1:cg::Starting value 183.473
+DEAL:1:cg::Convergence step 7 value 2.54095e-11
+DEAL:1:cg::Starting value 257.379
+DEAL:1:cg::Convergence step 7 value 3.94318e-11
+DEAL:1:cg::Starting value 6.44073
+DEAL:1:cg::Convergence step 7 value 4.64523e-13
+DEAL:1:cg::Starting value 8.68642
+DEAL:1:cg::Convergence step 7 value 5.79753e-13
+DEAL:1:cg::Starting value 9.47362
+DEAL:1:cg::Convergence step 7 value 6.67651e-13
+DEAL:1:cg::Starting value 9.30402
+DEAL:1:cg::Convergence step 7 value 9.36336e-13
+DEAL:1:cg::Starting value 8.99023
+DEAL:1:cg::Convergence step 7 value 1.22268e-12
+
+
+DEAL:2:cg::Starting value 45.0807
+DEAL:2:cg::Convergence step 7 value 2.65304e-12
+DEAL:2:cg::Starting value 68.5863
+DEAL:2:cg::Convergence step 7 value 3.81082e-12
+DEAL:2:cg::Starting value 95.4381
+DEAL:2:cg::Convergence step 7 value 7.14371e-12
+DEAL:2:cg::Starting value 131.732
+DEAL:2:cg::Convergence step 7 value 1.44204e-11
+DEAL:2:cg::Starting value 183.473
+DEAL:2:cg::Convergence step 7 value 2.54095e-11
+DEAL:2:cg::Starting value 257.379
+DEAL:2:cg::Convergence step 7 value 3.94318e-11
+DEAL:2:cg::Starting value 6.44073
+DEAL:2:cg::Convergence step 7 value 4.64523e-13
+DEAL:2:cg::Starting value 8.68642
+DEAL:2:cg::Convergence step 7 value 5.79753e-13
+DEAL:2:cg::Starting value 9.47362
+DEAL:2:cg::Convergence step 7 value 6.67651e-13
+DEAL:2:cg::Starting value 9.30402
+DEAL:2:cg::Convergence step 7 value 9.36336e-13
+DEAL:2:cg::Starting value 8.99023
+DEAL:2:cg::Convergence step 7 value 1.22268e-12
+
+
+DEAL:3:cg::Starting value 45.0807
+DEAL:3:cg::Convergence step 7 value 2.65304e-12
+DEAL:3:cg::Starting value 68.5863
+DEAL:3:cg::Convergence step 7 value 3.81082e-12
+DEAL:3:cg::Starting value 95.4381
+DEAL:3:cg::Convergence step 7 value 7.14371e-12
+DEAL:3:cg::Starting value 131.732
+DEAL:3:cg::Convergence step 7 value 1.44204e-11
+DEAL:3:cg::Starting value 183.473
+DEAL:3:cg::Convergence step 7 value 2.54095e-11
+DEAL:3:cg::Starting value 257.379
+DEAL:3:cg::Convergence step 7 value 3.94318e-11
+DEAL:3:cg::Starting value 6.44073
+DEAL:3:cg::Convergence step 7 value 4.64523e-13
+DEAL:3:cg::Starting value 8.68642
+DEAL:3:cg::Convergence step 7 value 5.79753e-13
+DEAL:3:cg::Starting value 9.47362
+DEAL:3:cg::Convergence step 7 value 6.67651e-13
+DEAL:3:cg::Starting value 9.30402
+DEAL:3:cg::Convergence step 7 value 9.36336e-13
+DEAL:3:cg::Starting value 8.99023
+DEAL:3:cg::Convergence step 7 value 1.22268e-12
+
diff --git a/tests/multigrid-global-coarsening/stokes_computation.cc b/tests/multigrid-global-coarsening/stokes_computation.cc
new file mode 100644 (file)
index 0000000..743a8ec
--- /dev/null
@@ -0,0 +1,1497 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2012 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// test for correctness of matrix free implementation for multigrid stokes
+
+
+#include <deal.II/base/function.h>
+#include <deal.II/base/index_set.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/quadrature_lib.h>
+#include <deal.II/base/symmetric_tensor.h>
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/distributed/grid_refinement.h>
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/dofs/dof_renumbering.h>
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+#include <deal.II/fe/fe_values.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_accessor.h>
+
+#include <deal.II/lac/affine_constraints.h>
+#include <deal.II/lac/block_vector.h>
+#include <deal.II/lac/generic_linear_algebra.h>
+#include <deal.II/lac/precondition.h>
+#include <deal.II/lac/solver_cg.h>
+#include <deal.II/lac/solver_gmres.h>
+#include <deal.II/lac/vector.h>
+
+#include <deal.II/matrix_free/fe_evaluation.h>
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/operators.h>
+
+#include <deal.II/multigrid/mg_coarse.h>
+#include <deal.II/multigrid/mg_constrained_dofs.h>
+#include <deal.II/multigrid/mg_matrix.h>
+#include <deal.II/multigrid/mg_smoother.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+#include <deal.II/multigrid/multigrid.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include <cmath>
+#include <sstream>
+
+#include "../tests.h"
+
+
+unsigned int       minlevel        = 0;
+const unsigned int velocity_degree = 2;
+
+double pressure_scaling = 1.0;
+
+namespace StokesClass
+{
+  class QuietException
+  {};
+
+  namespace StokesSolver
+  {
+    /**
+     * Implement the block Schur preconditioner for the Stokes system.
+     */
+    template <class StokesMatrixType,
+              class MassMatrixType,
+              class PreconditionerA,
+              class PreconditionerMp>
+    class BlockSchurPreconditioner : public Subscriptor
+    {
+    public:
+      /**
+       * brief Constructor
+       *
+       *  S The entire Stokes matrix
+       *  Spre The matrix whose blocks are used in the definition of
+       *     the preconditioning of the Stokes matrix, i.e. containing
+       *approximations of the A and S blocks. Mppreconditioner Preconditioner
+       *object for the Schur complement, typically chosen as the mass matrix.
+       *  Apreconditioner Preconditioner object for the matrix A.
+       *  do_solve_A A flag indicating whether we should actually solve with
+       *     the matrix $A$, or only apply one preconditioner step with it.
+       *  A_block_tolerance The tolerance for the CG solver which computes
+       *     the inverse of the A block.
+       *  S_block_tolerance The tolerance for the CG solver which computes
+       *     the inverse of the S block (Schur complement matrix).
+       **/
+      BlockSchurPreconditioner(const StokesMatrixType &S,
+                               const MassMatrixType &  Mass,
+                               const PreconditionerMp &Mppreconditioner,
+                               const PreconditionerA & Apreconditioner,
+                               const bool              do_solve_A,
+                               const double            A_block_tolerance,
+                               const double            S_block_tolerance);
+
+      /**
+       * Matrix vector product with this preconditioner object.
+       */
+      void
+      vmult(LinearAlgebra::distributed::BlockVector<double> &      dst,
+            const LinearAlgebra::distributed::BlockVector<double> &src) const;
+
+      unsigned int
+      n_iterations_A() const;
+      unsigned int
+      n_iterations_S() const;
+
+    private:
+      /**
+       * References to the various matrix object this preconditioner works on.
+       */
+      const StokesMatrixType &stokes_matrix;
+      const MassMatrixType &  mass_matrix;
+      const PreconditionerMp &mp_preconditioner;
+      const PreconditionerA & a_preconditioner;
+
+      /**
+       * Whether to actually invert the $\tilde A$ part of the preconditioner
+       *matrix or to just apply a single preconditioner step with it.
+       **/
+      const bool           do_solve_A;
+      mutable unsigned int n_iterations_A_;
+      mutable unsigned int n_iterations_S_;
+      const double         A_block_tolerance;
+      const double         S_block_tolerance;
+    };
+
+
+    template <class StokesMatrixType,
+              class MassMatrixType,
+              class PreconditionerA,
+              class PreconditionerMp>
+    BlockSchurPreconditioner<StokesMatrixType,
+                             MassMatrixType,
+                             PreconditionerA,
+                             PreconditionerMp>::
+      BlockSchurPreconditioner(const StokesMatrixType &S,
+                               const MassMatrixType &  Mass,
+                               const PreconditionerMp &Mppreconditioner,
+                               const PreconditionerA & Apreconditioner,
+                               const bool              do_solve_A,
+                               const double            A_block_tolerance,
+                               const double            S_block_tolerance)
+      : stokes_matrix(S)
+      , mass_matrix(Mass)
+      , mp_preconditioner(Mppreconditioner)
+      , a_preconditioner(Apreconditioner)
+      , do_solve_A(do_solve_A)
+      , n_iterations_A_(0)
+      , n_iterations_S_(0)
+      , A_block_tolerance(A_block_tolerance)
+      , S_block_tolerance(S_block_tolerance)
+    {}
+
+    template <class StokesMatrixType,
+              class MassMatrixType,
+              class PreconditionerA,
+              class PreconditionerMp>
+    unsigned int
+    BlockSchurPreconditioner<StokesMatrixType,
+                             MassMatrixType,
+                             PreconditionerA,
+                             PreconditionerMp>::n_iterations_A() const
+    {
+      return n_iterations_A_;
+    }
+
+    template <class StokesMatrixType,
+              class MassMatrixType,
+              class PreconditionerA,
+              class PreconditionerMp>
+    unsigned int
+    BlockSchurPreconditioner<StokesMatrixType,
+                             MassMatrixType,
+                             PreconditionerA,
+                             PreconditionerMp>::n_iterations_S() const
+    {
+      return n_iterations_S_;
+    }
+
+    template <class StokesMatrixType,
+              class MassMatrixType,
+              class PreconditionerA,
+              class PreconditionerMp>
+    void
+    BlockSchurPreconditioner<StokesMatrixType,
+                             MassMatrixType,
+                             PreconditionerA,
+                             PreconditionerMp>::
+      vmult(LinearAlgebra::distributed::BlockVector<double> &      dst,
+            const LinearAlgebra::distributed::BlockVector<double> &src) const
+    {
+      LinearAlgebra::distributed::BlockVector<double> utmp(src);
+
+      // first solve with the bottom left block, which we have built
+      // as a mass matrix with the inverse of the viscosity
+      {
+        SolverControl solver_control(1000,
+                                     src.block(1).l2_norm() * S_block_tolerance,
+                                     false,
+                                     false);
+
+        SolverCG<LinearAlgebra::distributed::Vector<double>> solver(
+          solver_control);
+        try
+          {
+            dst.block(1) = 0.0;
+            solver.solve(mass_matrix,
+                         dst.block(1),
+                         src.block(1),
+                         mp_preconditioner);
+            n_iterations_S_ += solver_control.last_step();
+          }
+        // if the solver fails, report the error from processor 0 with some
+        // additional information about its location, and throw a quiet
+        // exception on all other processors
+        catch (const std::exception &exc)
+          {
+            if (Utilities::MPI::this_mpi_process(
+                  src.block(0).get_mpi_communicator()) == 0)
+              AssertThrow(
+                false,
+                ExcMessage(
+                  std::string(
+                    "The iterative (bottom right) solver in BlockSchurPreconditioner::vmult "
+                    "did not converge to a tolerance of " +
+                    Utilities::to_string(solver_control.tolerance()) +
+                    ". It reported the following error:\n\n") +
+                  exc.what())) else throw QuietException();
+          }
+        dst.block(1) *= -1.0;
+      }
+
+      // apply the top right block
+      {
+        LinearAlgebra::distributed::BlockVector<double> dst_tmp(dst);
+        dst_tmp.block(0) = 0.0;
+        stokes_matrix.vmult(utmp, dst_tmp); // B^T
+        utmp.block(0) *= -1.0;
+        utmp.block(0) += src.block(0);
+      }
+
+      // now either solve with the top left block (if do_solve_A==true)
+      // or just apply one preconditioner sweep (for the first few
+      // iterations of our two-stage outer GMRES iteration)
+      if (do_solve_A == true)
+        {
+          Assert(false, ExcNotImplemented());
+        }
+      else
+        {
+          a_preconditioner.vmult(dst.block(0), utmp.block(0));
+          n_iterations_A_ += 1;
+        }
+    }
+  } // namespace StokesSolver
+
+
+  // Parameters for Sinker example
+  double beta  = 10.0;
+  double delta = 200.0;
+  double omega = 0.1;
+
+  template <int dim>
+  struct Sinker
+  {
+    unsigned int            problem_dim;
+    unsigned int            n_sinkers;
+    std::vector<Point<dim>> centers;
+    double                  DR_mu;
+    double                  mu_min;
+    double                  mu_max;
+  };
+
+  template <int dim>
+  class Viscosity
+  {
+  public:
+    Viscosity(const Sinker<dim> &sink);
+    virtual double
+    value(const Point<dim> &p, const unsigned int component = 0) const;
+    virtual void
+    value_list(const std::vector<Point<dim>> &points,
+               std::vector<double> &          values,
+               const unsigned int             component = 0) const;
+
+    Sinker<dim> sinker;
+  };
+  template <int dim>
+  Viscosity<dim>::Viscosity(const Sinker<dim> &sink)
+  {
+    sinker = sink;
+  }
+  template <int dim>
+  double
+  Viscosity<dim>::value(const Point<dim> &p,
+                        const unsigned int /*component*/) const
+  {
+    double Chi = 1.0;
+    for (unsigned int s = 0; s < sinker.n_sinkers; ++s)
+      {
+        double dist = p.distance(sinker.centers[s]);
+        double temp =
+          1 - std::exp(-delta * std::pow(std::max(0.0, dist - omega / 2.0), 2));
+        Chi *= temp;
+      }
+    return (sinker.mu_max - sinker.mu_min) * (1 - Chi) + sinker.mu_min;
+  }
+  template <int dim>
+  void
+  Viscosity<dim>::value_list(const std::vector<Point<dim>> &points,
+                             std::vector<double> &          values,
+                             const unsigned int             component) const
+  {
+    Assert(values.size() == points.size(),
+           ExcDimensionMismatch(values.size(), points.size()));
+    Assert(component == 0, ExcIndexRange(component, 0, 1));
+    const unsigned int n_points = points.size();
+    for (unsigned int i = 0; i < n_points; ++i)
+      values[i] = value(points[i], component);
+  }
+
+  template <int dim>
+  class RightHandSide
+  {
+  public:
+    RightHandSide(const Sinker<dim> &sink);
+    Sinker<dim> sinker;
+    virtual void
+    vector_value(const Point<dim> &p, Vector<double> &value) const;
+  };
+  template <int dim>
+  RightHandSide<dim>::RightHandSide(const Sinker<dim> &sink)
+  {
+    sinker = sink;
+  }
+  template <int dim>
+  void
+  RightHandSide<dim>::vector_value(const Point<dim> &p,
+                                   Vector<double> &  values) const
+  {
+    double Chi = 1.0;
+    for (unsigned int s = 0; s < sinker.n_sinkers; ++s)
+      {
+        double dist = p.distance(sinker.centers[s]);
+        double temp =
+          1 - std::exp(-delta * std::pow(std::max(0.0, dist - omega / 2.0), 2));
+        Chi *= temp;
+      }
+
+    if (sinker.problem_dim == 2)
+      {
+        values[0] = 0;
+        values[1] = beta * (Chi - 1.0);
+        values[2] = 0;
+      }
+    else if (sinker.problem_dim == 3)
+      {
+        values[0] = 0;
+        values[1] = 0;
+        values[2] = beta * (Chi - 1.0);
+        values[3] = 0;
+      }
+    return;
+  }
+
+  template <int dim>
+  class ExactSolution_BoundaryValues : public Function<dim>
+  {
+  public:
+    ExactSolution_BoundaryValues()
+      : Function<dim>(dim + 1)
+    {}
+    virtual void
+    vector_value(const Point<dim> &p, Vector<double> &value) const;
+  };
+  template <int dim>
+  void
+  ExactSolution_BoundaryValues<dim>::vector_value(const Point<dim> &p,
+                                                  Vector<double> &values) const
+  {
+    (void)p;
+    for (unsigned int i = 0; i < values.size(); ++i)
+      values(i) = 0.0;
+    return;
+  }
+
+  template <int dim>
+  class ExactSolution_BoundaryValues_u : public Function<dim>
+  {
+  public:
+    ExactSolution_BoundaryValues_u()
+      : Function<dim>(dim)
+    {}
+    virtual void
+    vector_value(const Point<dim> &p, Vector<double> &value) const;
+  };
+  template <int dim>
+  void
+  ExactSolution_BoundaryValues_u<dim>::vector_value(
+    const Point<dim> &p,
+    Vector<double> &  values) const
+  {
+    (void)p;
+    for (unsigned int i = 0; i < values.size(); ++i)
+      values(i) = 0.0;
+    return;
+  }
+
+
+
+  template <int dim, int degree_v, typename number>
+  class StokesOperator
+    : public MatrixFreeOperators::
+        Base<dim, LinearAlgebra::distributed::BlockVector<number>>
+  {
+  public:
+    StokesOperator()
+      : MatrixFreeOperators::
+          Base<dim, LinearAlgebra::distributed::BlockVector<number>>()
+    {}
+    void
+    clear();
+    void
+    evaluate_2_x_viscosity(const Viscosity<dim> &viscosity_function);
+    virtual void
+    compute_diagonal();
+
+  private:
+    virtual void
+    apply_add(LinearAlgebra::distributed::BlockVector<number> &      dst,
+              const LinearAlgebra::distributed::BlockVector<number> &src) const;
+
+    void
+    local_apply(const dealii::MatrixFree<dim, number> &                data,
+                LinearAlgebra::distributed::BlockVector<number> &      dst,
+                const LinearAlgebra::distributed::BlockVector<number> &src,
+                const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    Table<2, VectorizedArray<number>> viscosity_x_2;
+  };
+  template <int dim, int degree_v, typename number>
+  void
+  StokesOperator<dim, degree_v, number>::clear()
+  {
+    viscosity_x_2.reinit(0, 0);
+    MatrixFreeOperators::
+      Base<dim, LinearAlgebra::distributed::BlockVector<number>>::clear();
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  StokesOperator<dim, degree_v, number>::evaluate_2_x_viscosity(
+    const Viscosity<dim> &viscosity_function)
+  {
+    const unsigned int n_cells = this->data->n_cell_batches();
+    FEEvaluation<dim, degree_v, degree_v + 1, dim, number> velocity(*this->data,
+                                                                    0);
+    viscosity_x_2.reinit(n_cells, velocity.n_q_points);
+    for (unsigned int cell = 0; cell < n_cells; ++cell)
+      {
+        velocity.reinit(cell);
+        for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+          {
+            VectorizedArray<number> return_value =
+              make_vectorized_array<number>(1.);
+            for (unsigned int i = 0; i < VectorizedArray<number>::size(); ++i)
+              {
+                Point<dim> p;
+                for (unsigned int d = 0; d < dim; ++d)
+                  {
+                    p(d) = velocity.quadrature_point(q)(d)[i];
+                  }
+                return_value[i] = 2.0 * viscosity_function.value(p);
+              }
+            viscosity_x_2(cell, q) = return_value;
+          }
+      }
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  StokesOperator<dim, degree_v, number>::local_apply(
+    const dealii::MatrixFree<dim, number> &                data,
+    LinearAlgebra::distributed::BlockVector<number> &      dst,
+    const LinearAlgebra::distributed::BlockVector<number> &src,
+    const std::pair<unsigned int, unsigned int> &          cell_range) const
+  {
+    using vector_t = VectorizedArray<number>;
+    FEEvaluation<dim, degree_v, degree_v + 1, dim, number>   velocity(data, 0);
+    FEEvaluation<dim, degree_v - 1, degree_v + 1, 1, number> pressure(data, 1);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        velocity.reinit(cell);
+        velocity.read_dof_values(src.block(0));
+        velocity.evaluate(EvaluationFlags::gradients);
+        pressure.reinit(cell);
+        pressure.read_dof_values(src.block(1));
+        pressure.evaluate(EvaluationFlags::values);
+
+        for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+          {
+            SymmetricTensor<2, dim, vector_t> sym_grad_u =
+              velocity.get_symmetric_gradient(q);
+            vector_t pres = pressure.get_value(q);
+            vector_t div  = -trace(sym_grad_u);
+            pressure.submit_value(div, q);
+
+            sym_grad_u *= viscosity_x_2(cell, q);
+            // subtract p * I
+            for (unsigned int d = 0; d < dim; ++d)
+              sym_grad_u[d][d] -= pres;
+
+            velocity.submit_symmetric_gradient(sym_grad_u, q);
+          }
+
+        velocity.integrate(EvaluationFlags::gradients);
+        velocity.distribute_local_to_global(dst.block(0));
+        pressure.integrate(EvaluationFlags::values);
+        pressure.distribute_local_to_global(dst.block(1));
+      }
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  StokesOperator<dim, degree_v, number>::apply_add(
+    LinearAlgebra::distributed::BlockVector<number> &      dst,
+    const LinearAlgebra::distributed::BlockVector<number> &src) const
+  {
+    MatrixFreeOperators::
+      Base<dim, LinearAlgebra::distributed::BlockVector<number>>::data
+        ->cell_loop(&StokesOperator::local_apply, this, dst, src);
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  StokesOperator<dim, degree_v, number>::compute_diagonal()
+  {
+    Assert(false, ExcNotImplemented());
+  }
+
+
+  template <int dim, int degree_p, typename number>
+  class MassMatrixOperator
+    : public MatrixFreeOperators::
+        Base<dim, LinearAlgebra::distributed::Vector<number>>
+  {
+  public:
+    MassMatrixOperator()
+      : MatrixFreeOperators::Base<dim,
+                                  LinearAlgebra::distributed::Vector<number>>()
+    {}
+    void
+    clear();
+    void
+    evaluate_1_over_viscosity(const Viscosity<dim> &viscosity_function);
+    virtual void
+    compute_diagonal();
+
+  private:
+    virtual void
+    apply_add(LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src) const;
+
+    void
+    local_apply(const dealii::MatrixFree<dim, number> &           data,
+                LinearAlgebra::distributed::Vector<number> &      dst,
+                const LinearAlgebra::distributed::Vector<number> &src,
+                const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    void
+    local_compute_diagonal(
+      const MatrixFree<dim, number> &              data,
+      LinearAlgebra::distributed::Vector<number> & dst,
+      const unsigned int &                         dummy,
+      const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    Table<2, VectorizedArray<number>> one_over_viscosity;
+  };
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::clear()
+  {
+    one_over_viscosity.reinit(0, 0);
+    MatrixFreeOperators::Base<dim, LinearAlgebra::distributed::Vector<number>>::
+      clear();
+  }
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::evaluate_1_over_viscosity(
+    const Viscosity<dim> &viscosity_function)
+  {
+    const unsigned int n_cells = this->data->n_cell_batches();
+    FEEvaluation<dim, degree_p, degree_p + 2, 1, number> pressure(*this->data,
+                                                                  0);
+    one_over_viscosity.reinit(n_cells, pressure.n_q_points);
+    for (unsigned int cell = 0; cell < n_cells; ++cell)
+      {
+        pressure.reinit(cell);
+        for (unsigned int q = 0; q < pressure.n_q_points; ++q)
+          {
+            VectorizedArray<number> return_value =
+              make_vectorized_array<number>(1.);
+            for (unsigned int i = 0; i < VectorizedArray<number>::size(); ++i)
+              {
+                Point<dim> p;
+                for (unsigned int d = 0; d < dim; ++d)
+                  p(d) = pressure.quadrature_point(q)(d)[i];
+                return_value[i] = 1.0 / viscosity_function.value(p);
+              }
+            one_over_viscosity(cell, q) = return_value;
+          }
+      }
+  }
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::local_apply(
+    const dealii::MatrixFree<dim, number> &           data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     cell_range) const
+  {
+    FEEvaluation<dim, degree_p, degree_p + 2, 1, number> pressure(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        AssertDimension(one_over_viscosity.size(0), data.n_cell_batches());
+        AssertDimension(one_over_viscosity.size(1), pressure.n_q_points);
+
+        pressure.reinit(cell);
+        pressure.read_dof_values(src);
+        pressure.evaluate(EvaluationFlags::values);
+        for (unsigned int q = 0; q < pressure.n_q_points; ++q)
+          pressure.submit_value(one_over_viscosity(cell, q) *
+                                  pressure.get_value(q),
+                                q);
+        pressure.integrate(EvaluationFlags::values);
+        pressure.distribute_local_to_global(dst);
+      }
+  }
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::apply_add(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    MatrixFreeOperators::Base<dim,
+                              LinearAlgebra::distributed::Vector<number>>::data
+      ->cell_loop(&MassMatrixOperator::local_apply, this, dst, src);
+  }
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::compute_diagonal()
+  {
+    this->inverse_diagonal_entries.reset(
+      new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+    this->diagonal_entries.reset(
+      new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+
+    LinearAlgebra::distributed::Vector<number> &inverse_diagonal =
+      this->inverse_diagonal_entries->get_vector();
+    LinearAlgebra::distributed::Vector<number> &diagonal =
+      this->diagonal_entries->get_vector();
+
+    unsigned int dummy = 0;
+    this->data->initialize_dof_vector(inverse_diagonal);
+    this->data->initialize_dof_vector(diagonal);
+
+    this->data->cell_loop(&MassMatrixOperator::local_compute_diagonal,
+                          this,
+                          diagonal,
+                          dummy);
+
+    this->set_constrained_entries_to_one(diagonal);
+    inverse_diagonal              = diagonal;
+    const unsigned int local_size = inverse_diagonal.locally_owned_size();
+    for (unsigned int i = 0; i < local_size; ++i)
+      {
+        Assert(inverse_diagonal.local_element(i) > 0.,
+               ExcMessage("No diagonal entry in a positive definite operator "
+                          "should be zero"));
+        inverse_diagonal.local_element(i) =
+          1. / inverse_diagonal.local_element(i);
+      }
+  }
+  template <int dim, int degree_p, typename number>
+  void
+  MassMatrixOperator<dim, degree_p, number>::local_compute_diagonal(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, degree_p, degree_p + 2, 1, number> pressure(data, 0);
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        pressure.reinit(cell);
+        AlignedVector<VectorizedArray<number>> diagonal(pressure.dofs_per_cell);
+        for (unsigned int i = 0; i < pressure.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < pressure.dofs_per_cell; ++j)
+              pressure.begin_dof_values()[j] = VectorizedArray<number>();
+            pressure.begin_dof_values()[i] = make_vectorized_array<number>(1.);
+
+            pressure.evaluate(EvaluationFlags::values);
+            for (unsigned int q = 0; q < pressure.n_q_points; ++q)
+              pressure.submit_value(one_over_viscosity(cell, q) *
+                                      pressure.get_value(q),
+                                    q);
+            pressure.integrate(EvaluationFlags::values);
+
+            diagonal[i] = pressure.begin_dof_values()[i];
+          }
+
+        for (unsigned int i = 0; i < pressure.dofs_per_cell; ++i)
+          pressure.begin_dof_values()[i] = diagonal[i];
+        pressure.distribute_local_to_global(dst);
+      }
+  }
+
+
+  template <int dim, int degree_v, typename number>
+  class ABlockOperator : public MatrixFreeOperators::
+                           Base<dim, LinearAlgebra::distributed::Vector<number>>
+  {
+  public:
+    ABlockOperator()
+      : MatrixFreeOperators::Base<dim,
+                                  LinearAlgebra::distributed::Vector<number>>()
+    {}
+    void
+    clear();
+    void
+    evaluate_2_x_viscosity(const Viscosity<dim> &viscosity_function);
+    virtual void
+    compute_diagonal();
+
+  private:
+    virtual void
+    apply_add(LinearAlgebra::distributed::Vector<number> &      dst,
+              const LinearAlgebra::distributed::Vector<number> &src) const;
+
+    void
+    local_apply(const dealii::MatrixFree<dim, number> &           data,
+                LinearAlgebra::distributed::Vector<number> &      dst,
+                const LinearAlgebra::distributed::Vector<number> &src,
+                const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    void
+    local_compute_diagonal(
+      const MatrixFree<dim, number> &              data,
+      LinearAlgebra::distributed::Vector<number> & dst,
+      const unsigned int &                         dummy,
+      const std::pair<unsigned int, unsigned int> &cell_range) const;
+
+    Table<2, VectorizedArray<number>> viscosity_x_2;
+  };
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::clear()
+  {
+    viscosity_x_2.reinit(0, 0);
+    MatrixFreeOperators::Base<dim, LinearAlgebra::distributed::Vector<number>>::
+      clear();
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::evaluate_2_x_viscosity(
+    const Viscosity<dim> &viscosity_function)
+  {
+    const unsigned int n_cells = this->data->n_cell_batches();
+    FEEvaluation<dim, degree_v, degree_v + 1, dim, number> velocity(*this->data,
+                                                                    0);
+    viscosity_x_2.reinit(n_cells, velocity.n_q_points);
+    for (unsigned int cell = 0; cell < n_cells; ++cell)
+      {
+        velocity.reinit(cell);
+        for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+          {
+            VectorizedArray<number> return_value =
+              make_vectorized_array<number>(1.);
+            for (unsigned int i = 0; i < VectorizedArray<number>::size(); ++i)
+              {
+                Point<dim> p;
+                for (unsigned int d = 0; d < dim; ++d)
+                  {
+                    p(d) = velocity.quadrature_point(q)(d)[i];
+                  }
+                return_value[i] = 2.0 * viscosity_function.value(p);
+              }
+            viscosity_x_2(cell, q) = return_value;
+          }
+      }
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::local_apply(
+    const dealii::MatrixFree<dim, number> &           data,
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src,
+    const std::pair<unsigned int, unsigned int> &     cell_range) const
+  {
+    FEEvaluation<dim, degree_v, degree_v + 1, dim, number> velocity(data);
+
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        AssertDimension(viscosity_x_2.size(0), data.n_cell_batches());
+        AssertDimension(viscosity_x_2.size(1), velocity.n_q_points);
+
+        velocity.reinit(cell);
+        velocity.read_dof_values(src);
+        velocity.evaluate(EvaluationFlags::gradients);
+        for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+          {
+            velocity.submit_symmetric_gradient(
+              viscosity_x_2(cell, q) * velocity.get_symmetric_gradient(q), q);
+          }
+        velocity.integrate(EvaluationFlags::gradients);
+        velocity.distribute_local_to_global(dst);
+      }
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::apply_add(
+    LinearAlgebra::distributed::Vector<number> &      dst,
+    const LinearAlgebra::distributed::Vector<number> &src) const
+  {
+    MatrixFreeOperators::Base<dim,
+                              LinearAlgebra::distributed::Vector<number>>::data
+      ->cell_loop(&ABlockOperator::local_apply, this, dst, src);
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::compute_diagonal()
+  {
+    this->inverse_diagonal_entries.reset(
+      new DiagonalMatrix<LinearAlgebra::distributed::Vector<number>>());
+    LinearAlgebra::distributed::Vector<number> &inverse_diagonal =
+      this->inverse_diagonal_entries->get_vector();
+    this->data->initialize_dof_vector(inverse_diagonal);
+    unsigned int dummy = 0;
+    this->data->cell_loop(&ABlockOperator::local_compute_diagonal,
+                          this,
+                          inverse_diagonal,
+                          dummy);
+
+    this->set_constrained_entries_to_one(inverse_diagonal);
+
+    for (unsigned int i = 0; i < inverse_diagonal.locally_owned_size(); ++i)
+      {
+        Assert(inverse_diagonal.local_element(i) > 0.,
+               ExcMessage("No diagonal entry in a positive definite operator "
+                          "should be zero"));
+        inverse_diagonal.local_element(i) =
+          1. / inverse_diagonal.local_element(i);
+      }
+  }
+  template <int dim, int degree_v, typename number>
+  void
+  ABlockOperator<dim, degree_v, number>::local_compute_diagonal(
+    const MatrixFree<dim, number> &             data,
+    LinearAlgebra::distributed::Vector<number> &dst,
+    const unsigned int &,
+    const std::pair<unsigned int, unsigned int> &cell_range) const
+  {
+    FEEvaluation<dim, degree_v, degree_v + 1, dim, number> velocity(data, 0);
+    for (unsigned int cell = cell_range.first; cell < cell_range.second; ++cell)
+      {
+        velocity.reinit(cell);
+        AlignedVector<VectorizedArray<number>> diagonal(velocity.dofs_per_cell);
+        for (unsigned int i = 0; i < velocity.dofs_per_cell; ++i)
+          {
+            for (unsigned int j = 0; j < velocity.dofs_per_cell; ++j)
+              velocity.begin_dof_values()[j] = VectorizedArray<number>();
+            velocity.begin_dof_values()[i] = make_vectorized_array<number>(1.);
+
+            velocity.evaluate(EvaluationFlags::gradients);
+            for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+              {
+                velocity.submit_symmetric_gradient(
+                  viscosity_x_2(cell, q) * velocity.get_symmetric_gradient(q),
+                  q);
+              }
+            velocity.integrate(EvaluationFlags::gradients);
+
+            diagonal[i] = velocity.begin_dof_values()[i];
+          }
+
+        for (unsigned int i = 0; i < velocity.dofs_per_cell; ++i)
+          velocity.begin_dof_values()[i] = diagonal[i];
+        velocity.distribute_local_to_global(dst);
+      }
+  }
+
+
+
+  template <int dim>
+  class StokesProblem
+  {
+  public:
+    StokesProblem();
+
+    void
+    run();
+
+  private:
+    void
+    make_grid(const unsigned int ref = 4);
+    void
+    create_sinker(const unsigned int n_sinkers, const double visc_jump);
+    void
+    setup_system();
+    void
+    assemble_rhs();
+    void
+    solve();
+
+    using vector_t       = LinearAlgebra::distributed::Vector<double>;
+    using block_vector_t = LinearAlgebra::distributed::BlockVector<double>;
+
+    using StokesMatrixType = StokesOperator<dim, velocity_degree, double>;
+    using MassMatrixType = MassMatrixOperator<dim, velocity_degree - 1, double>;
+    using LevelMatrixType = ABlockOperator<dim, velocity_degree, double>;
+
+    unsigned int degree_u;
+
+    FESystem<dim> fe_u;
+    FE_Q<dim>     fe_p;
+
+    parallel::distributed::Triangulation<dim> triangulation;
+    DoFHandler<dim>                           dof_handler_u;
+    DoFHandler<dim>                           dof_handler_p;
+
+    std::vector<IndexSet> owned_partitioning;
+    std::vector<IndexSet> relevant_partitioning;
+
+    AffineConstraints<double> constraints_u;
+    AffineConstraints<double> constraints_p;
+
+    block_vector_t solution;
+    block_vector_t system_rhs;
+
+    StokesMatrixType stokes_matrix;
+    MassMatrixType   mass_matrix;
+
+    MGLevelObject<LevelMatrixType> mg_matrices;
+    MGConstrainedDoFs              mg_constrained_dofs;
+
+    Sinker<dim> sinker;
+  };
+
+
+
+  template <int dim>
+  StokesProblem<dim>::StokesProblem()
+    : degree_u(velocity_degree)
+    , fe_u(FE_Q<dim>(degree_u), dim)
+    , fe_p(FE_Q<dim>(degree_u - 1))
+    , triangulation(MPI_COMM_WORLD,
+                    typename Triangulation<dim>::MeshSmoothing(
+                      Triangulation<dim>::limit_level_difference_at_vertices |
+                      Triangulation<dim>::smoothing_on_refinement |
+                      Triangulation<dim>::smoothing_on_coarsening),
+                    parallel::distributed::Triangulation<
+                      dim>::construct_multigrid_hierarchy)
+    , dof_handler_u(triangulation)
+    , dof_handler_p(triangulation)
+  {}
+
+  template <int dim>
+  void
+  StokesProblem<dim>::create_sinker(const unsigned int n_sinkers,
+                                    const double       visc_jump)
+  {
+    sinker.problem_dim = dim;
+    sinker.n_sinkers   = n_sinkers;
+    std::srand(171);
+    for (unsigned int s = 0; s < sinker.n_sinkers; ++s)
+      {
+        std::vector<double> coords(dim);
+        if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
+          for (unsigned int i = 0; i < dim; ++i)
+            coords[i] = std::rand() / (double)RAND_MAX;
+
+        MPI_Bcast(&(coords[0]), dim, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+
+        Tensor<1, dim, double> coords_tens;
+        for (unsigned int i = 0; i < dim; ++i)
+          coords_tens[i] = coords[i];
+        sinker.centers.push_back(Point<dim>(coords_tens));
+      }
+
+    sinker.DR_mu  = visc_jump;
+    sinker.mu_max = std::sqrt(sinker.DR_mu);
+    sinker.mu_min = 1.0 / std::sqrt(sinker.DR_mu);
+  }
+
+
+  template <int dim>
+  void
+  StokesProblem<dim>::make_grid(const unsigned int ref)
+  {
+    GridGenerator::hyper_cube(triangulation, 0, 1);
+    triangulation.refine_global(ref);
+  }
+
+
+  template <int dim>
+  void
+  StokesProblem<dim>::setup_system()
+  {
+    dof_handler_u.clear();
+    dof_handler_u.distribute_dofs(fe_u);
+    dof_handler_u.distribute_mg_dofs();
+
+    dof_handler_p.clear();
+    dof_handler_p.distribute_dofs(fe_p);
+
+    IndexSet locally_relevant_dofs_u;
+    DoFTools::extract_locally_relevant_dofs(dof_handler_u,
+                                            locally_relevant_dofs_u);
+    constraints_u.reinit(locally_relevant_dofs_u);
+    DoFTools::make_hanging_node_constraints(dof_handler_u, constraints_u);
+
+    VectorTools::interpolate_boundary_values(
+      dof_handler_u, 0, ExactSolution_BoundaryValues_u<dim>(), constraints_u);
+    constraints_u.close();
+
+    IndexSet locally_relevant_dofs_p;
+    DoFTools::extract_locally_relevant_dofs(dof_handler_p,
+                                            locally_relevant_dofs_p);
+    constraints_p.reinit(locally_relevant_dofs_p);
+    DoFTools::make_hanging_node_constraints(dof_handler_p, constraints_p);
+    constraints_p.close();
+
+
+    // Stokes matrix stuff...
+    typename MatrixFree<dim, double>::AdditionalData additional_data_stokes;
+    additional_data_stokes.tasks_parallel_scheme =
+      MatrixFree<dim, double>::AdditionalData::none;
+    additional_data_stokes.mapping_update_flags =
+      (update_values | update_gradients | update_JxW_values |
+       update_quadrature_points);
+
+    std::vector<const DoFHandler<dim> *> stokes_dofs;
+    stokes_dofs.push_back(&dof_handler_u);
+    stokes_dofs.push_back(&dof_handler_p);
+    std::vector<const AffineConstraints<double> *> stokes_constraints;
+    stokes_constraints.push_back(&constraints_u);
+    stokes_constraints.push_back(&constraints_p);
+
+    std::shared_ptr<MatrixFree<dim, double>> stokes_mf_storage(
+      new MatrixFree<dim, double>());
+    stokes_mf_storage->reinit(MappingQ1<dim>{},
+                              stokes_dofs,
+                              stokes_constraints,
+                              QGauss<1>(degree_u + 1),
+                              additional_data_stokes);
+
+    stokes_matrix.initialize(stokes_mf_storage);
+    stokes_matrix.evaluate_2_x_viscosity(Viscosity<dim>(sinker));
+
+    // Mass matrix stuff...
+    typename MatrixFree<dim, double>::AdditionalData additional_data_mass;
+    additional_data_mass.tasks_parallel_scheme =
+      MatrixFree<dim, double>::AdditionalData::none;
+    additional_data_mass.mapping_update_flags =
+      (update_values | update_JxW_values | update_quadrature_points);
+    std::shared_ptr<MatrixFree<dim, double>> mass_mf_storage(
+      new MatrixFree<dim, double>());
+    mass_mf_storage->reinit(MappingQ1<dim>{},
+                            dof_handler_p,
+                            constraints_p,
+                            QGauss<1>(degree_u + 1),
+                            additional_data_mass);
+
+    mass_matrix.initialize(mass_mf_storage);
+    mass_matrix.evaluate_1_over_viscosity(Viscosity<dim>(sinker));
+    mass_matrix.compute_diagonal();
+
+    // GMG stuff...
+    const unsigned int n_levels = triangulation.n_global_levels();
+    mg_matrices.clear_elements();
+
+    mg_matrices.resize(0, n_levels - 1);
+
+    mg_constrained_dofs.clear();
+    const std::set<types::boundary_id> dirichlet_boundary = {0};
+    mg_constrained_dofs.initialize(dof_handler_u);
+    mg_constrained_dofs.make_zero_boundary_constraints(dof_handler_u,
+                                                       dirichlet_boundary);
+
+
+    for (unsigned int level = 0; level < n_levels; ++level)
+      {
+        IndexSet relevant_dofs;
+        DoFTools::extract_locally_relevant_level_dofs(dof_handler_u,
+                                                      level,
+                                                      relevant_dofs);
+        AffineConstraints<double> level_constraints;
+        level_constraints.reinit(relevant_dofs);
+        level_constraints.add_lines(
+          mg_constrained_dofs.get_boundary_indices(level));
+        level_constraints.close();
+
+        typename MatrixFree<dim, double>::AdditionalData additional_data;
+        additional_data.tasks_parallel_scheme =
+          MatrixFree<dim, double>::AdditionalData::none;
+        additional_data.mapping_update_flags =
+          (update_gradients | update_JxW_values | update_quadrature_points);
+        additional_data.mg_level = level;
+        std::shared_ptr<MatrixFree<dim, double>> mg_mf_storage_level(
+          new MatrixFree<dim, double>());
+        mg_mf_storage_level->reinit(MappingQ1<dim>{},
+                                    dof_handler_u,
+                                    level_constraints,
+                                    QGauss<1>(degree_u + 1),
+                                    additional_data);
+
+        mg_matrices[level].initialize(mg_mf_storage_level,
+                                      mg_constrained_dofs,
+                                      level);
+        mg_matrices[level].evaluate_2_x_viscosity(Viscosity<dim>(sinker));
+        mg_matrices[level].compute_diagonal();
+      }
+
+    solution.reinit(2);
+    system_rhs.reinit(2);
+
+    stokes_matrix.initialize_dof_vector(solution);
+    stokes_matrix.initialize_dof_vector(system_rhs);
+
+    solution.update_ghost_values();
+    solution.collect_sizes();
+
+    system_rhs.update_ghost_values();
+    system_rhs.collect_sizes();
+  }
+
+
+
+  template <int dim>
+  void
+  StokesProblem<dim>::assemble_rhs()
+  {
+    system_rhs = 0.0;
+
+    // Create operator with no Dirchlet info
+    StokesMatrixType                                 operator_homogeneous;
+    typename MatrixFree<dim, double>::AdditionalData data;
+    data.tasks_parallel_scheme = MatrixFree<dim, double>::AdditionalData::none;
+    data.mapping_update_flags  = (update_values | update_gradients |
+                                 update_JxW_values | update_quadrature_points);
+
+    // Create constraints with no Dirchlet info
+    AffineConstraints<double> constraints_u_no_dirchlet;
+    IndexSet                  locally_relevant_dofs_u;
+    DoFTools::extract_locally_relevant_dofs(dof_handler_u,
+                                            locally_relevant_dofs_u);
+    constraints_u_no_dirchlet.reinit(locally_relevant_dofs_u);
+    DoFTools::make_hanging_node_constraints(dof_handler_u,
+                                            constraints_u_no_dirchlet);
+    constraints_u_no_dirchlet.close();
+
+    std::vector<const AffineConstraints<double> *> constraints_no_dirchlet;
+    constraints_no_dirchlet.push_back(&constraints_u_no_dirchlet);
+    constraints_no_dirchlet.push_back(&constraints_p);
+    std::vector<const DoFHandler<dim> *> dofs;
+    dofs.push_back(&dof_handler_u);
+    dofs.push_back(&dof_handler_p);
+
+    std::shared_ptr<MatrixFree<dim, double>> matrix_free_homogeneous(
+      new MatrixFree<dim, double>());
+    matrix_free_homogeneous->reinit(MappingQ1<dim>{},
+                                    dofs,
+                                    constraints_no_dirchlet,
+                                    QGauss<1>(degree_u + 1),
+                                    data);
+
+    operator_homogeneous.initialize(matrix_free_homogeneous);
+    operator_homogeneous.evaluate_2_x_viscosity(Viscosity<dim>(sinker));
+    LinearAlgebra::distributed::BlockVector<double> inhomogeneity(2);
+    operator_homogeneous.initialize_dof_vector(inhomogeneity);
+    constraints_u.distribute(inhomogeneity.block(0));
+    operator_homogeneous.vmult(system_rhs, inhomogeneity);
+    system_rhs *= -1.;
+
+    // Normal apply boundary
+    RightHandSide<dim> right_hand_side(sinker);
+
+    FEEvaluation<dim, velocity_degree, velocity_degree + 1, dim, double>
+      velocity(*stokes_matrix.get_matrix_free(), 0);
+    FEEvaluation<dim, velocity_degree - 1, velocity_degree + 1, 1, double>
+      pressure(*stokes_matrix.get_matrix_free(), 1);
+
+    for (unsigned int cell = 0;
+         cell < stokes_matrix.get_matrix_free()->n_cell_batches();
+         ++cell)
+      {
+        velocity.reinit(cell);
+        pressure.reinit(cell);
+        for (unsigned int q = 0; q < velocity.n_q_points; ++q)
+          {
+            Tensor<1, dim, VectorizedArray<double>> rhs_u;
+            for (unsigned int d = 0; d < dim; ++d)
+              rhs_u[d] = make_vectorized_array<double>(1.0);
+            VectorizedArray<double> rhs_p = make_vectorized_array<double>(1.0);
+            for (unsigned int i = 0; i < VectorizedArray<double>::size(); ++i)
+              {
+                Point<dim> p;
+                for (unsigned int d = 0; d < dim; ++d)
+                  p(d) = velocity.quadrature_point(q)(d)[i];
+
+                Vector<double> rhs_temp(dim + 1);
+                right_hand_side.vector_value(p, rhs_temp);
+
+                for (unsigned int d = 0; d < dim; ++d)
+                  rhs_u[d][i] = rhs_temp(d);
+                rhs_p[i] = rhs_temp(dim);
+              }
+            velocity.submit_value(rhs_u, q);
+            pressure.submit_value(rhs_p, q);
+          }
+        velocity.integrate(EvaluationFlags::values);
+        velocity.distribute_local_to_global(system_rhs.block(0));
+        pressure.integrate(EvaluationFlags::values);
+        pressure.distribute_local_to_global(system_rhs.block(1));
+      }
+    system_rhs.compress(VectorOperation::add);
+  }
+
+  template <int dim>
+  void
+  StokesProblem<dim>::solve()
+  {
+    const double       solver_tolerance = 1e-6 * system_rhs.l2_norm();
+    const unsigned int n_cheap_stokes_solver_steps     = 1000;
+    const double       linear_solver_A_block_tolerance = 1e-2;
+    const double       linear_solver_S_block_tolerance = 1e-6;
+
+    // extract Stokes parts of solution vector, without any ghost elements
+    block_vector_t distributed_stokes_solution(solution);
+
+    const unsigned int block_vel = 0;
+    const unsigned int block_p   = 1;
+
+    // extract Stokes parts of rhs vector
+    block_vector_t distributed_stokes_rhs(system_rhs);
+
+    PrimitiveVectorMemory<block_vector_t> mem;
+
+    SolverControl solver_control_cheap(n_cheap_stokes_solver_steps,
+                                       solver_tolerance,
+                                       false,
+                                       false);
+
+    using Transfer = MGTransferMF<dim, double>;
+
+    Transfer mg_transfer(mg_constrained_dofs);
+    mg_transfer.initialize_constraints(mg_constrained_dofs);
+    mg_transfer.build(dof_handler_u);
+
+    LevelMatrixType &  coarse_matrix = mg_matrices[0];
+    SolverControl      coarse_solver_control(1000, 1e-12, false, false);
+    SolverCG<vector_t> coarse_solver(coarse_solver_control);
+
+    PreconditionIdentity coarse_prec_identity;
+    MGCoarseGridIterativeSolver<vector_t,
+                                SolverCG<vector_t>,
+                                LevelMatrixType,
+                                PreconditionIdentity>
+      mg_coarse;
+    mg_coarse.initialize(coarse_solver, coarse_matrix, coarse_prec_identity);
+
+    using SmootherType = PreconditionChebyshev<LevelMatrixType, vector_t>;
+    mg::SmootherRelaxation<SmootherType, vector_t>       mg_smoother;
+    MGLevelObject<typename SmootherType::AdditionalData> smoother_data;
+    smoother_data.resize(0, triangulation.n_global_levels() - 1);
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      {
+        if (level > 0)
+          {
+            smoother_data[level].smoothing_range     = 15.;
+            smoother_data[level].degree              = 4;
+            smoother_data[level].eig_cg_n_iterations = 10;
+          }
+        else
+          {
+            smoother_data[0].smoothing_range = 1e-3;
+            smoother_data[0].degree          = numbers::invalid_unsigned_int;
+            smoother_data[0].eig_cg_n_iterations = mg_matrices[0].m();
+          }
+        smoother_data[level].preconditioner =
+          mg_matrices[level].get_matrix_diagonal_inverse();
+      }
+    mg_smoother.initialize(mg_matrices, smoother_data);
+
+    mg::Matrix<vector_t> mg_matrix(mg_matrices);
+
+    MGLevelObject<MatrixFreeOperators::MGInterfaceOperator<LevelMatrixType>>
+      mg_interface_matrices;
+    mg_interface_matrices.resize(0, triangulation.n_global_levels() - 1);
+    for (unsigned int level = 0; level < triangulation.n_global_levels();
+         ++level)
+      mg_interface_matrices[level].initialize(mg_matrices[level]);
+    mg::Matrix<vector_t> mg_interface(mg_interface_matrices);
+
+    Multigrid<vector_t> mg(
+      mg_matrix, mg_coarse, mg_transfer, mg_smoother, mg_smoother, 0);
+    mg.set_edge_matrices(mg_interface, mg_interface);
+
+
+    PreconditionMG<dim, vector_t, Transfer> prec_A(dof_handler_u,
+                                                   mg,
+                                                   mg_transfer);
+
+    using MassPrec = PreconditionChebyshev<MassMatrixType, vector_t>;
+    MassPrec                          prec_S;
+    typename MassPrec::AdditionalData prec_S_data;
+    prec_S_data.smoothing_range     = 1e-3;
+    prec_S_data.degree              = numbers::invalid_unsigned_int;
+    prec_S_data.eig_cg_n_iterations = mass_matrix.m();
+    prec_S_data.preconditioner      = mass_matrix.get_matrix_diagonal_inverse();
+    prec_S.initialize(mass_matrix, prec_S_data);
+
+    using A_prec_type = PreconditionMG<dim, vector_t, Transfer>;
+
+    // create a cheap preconditioner that consists of only a single V-cycle
+    const StokesSolver::BlockSchurPreconditioner<StokesMatrixType,
+                                                 MassMatrixType,
+                                                 A_prec_type,
+                                                 MassPrec>
+      preconditioner_cheap(stokes_matrix,
+                           mass_matrix,
+                           prec_S,
+                           prec_A,
+                           false,
+                           linear_solver_A_block_tolerance,
+                           linear_solver_S_block_tolerance);
+    try
+      {
+        SolverFGMRES<block_vector_t> solver(
+          solver_control_cheap,
+          mem,
+          SolverFGMRES<block_vector_t>::AdditionalData(50));
+
+        solver.solve(stokes_matrix,
+                     distributed_stokes_solution,
+                     distributed_stokes_rhs,
+                     preconditioner_cheap);
+      }
+    catch (const SolverControl::NoConvergence &)
+      {
+        deallog
+          << "********************************************************************"
+          << std::endl
+          << "SOLVER DID NOT CONVERGE AFTER " << n_cheap_stokes_solver_steps
+          << " ITERATIONS. res=" << solver_control_cheap.last_value()
+          << std::endl
+          << "********************************************************************"
+          << std::endl;
+      }
+
+    constraints_u.distribute(distributed_stokes_solution.block(0));
+
+    distributed_stokes_solution.block(block_p) *= pressure_scaling;
+
+    solution.block(block_vel) = distributed_stokes_solution.block(block_vel);
+    solution.block(block_p)   = distributed_stokes_solution.block(block_p);
+
+    deallog << "Solved-in "
+            << (solver_control_cheap.last_step() !=
+                    numbers::invalid_unsigned_int ?
+                  solver_control_cheap.last_step() :
+                  0)
+            << " iterations, final residual: "
+            << solver_control_cheap.last_value() << std::endl;
+  }
+
+
+  template <int dim>
+  void
+  StokesProblem<dim>::run()
+  {
+    deallog << "Sinker problem in " << dim << "D." << std::endl;
+
+    create_sinker(4, 1000);
+    deallog << "n_sinker: " << sinker.n_sinkers
+            << "       max/min viscosity ratio: " << sinker.DR_mu << std::endl
+            << std::endl;
+
+    unsigned int initial_ref;
+    if (dim == 2)
+      {
+        initial_ref = 5;
+      }
+    else if (dim == 3)
+      {
+        initial_ref = 3;
+      }
+
+    unsigned int n_cycles = 1;
+    if (dim == 2)
+      n_cycles = 2;
+    for (unsigned int cycle = 0; cycle < n_cycles; ++cycle)
+      {
+        if (cycle == 0)
+          make_grid(initial_ref);
+        else
+          triangulation.refine_global();
+
+        setup_system();
+        deallog << "Number of active cells: "
+                << triangulation.n_global_active_cells() << " (on "
+                << triangulation.n_global_levels() << " levels)" << std::endl;
+        deallog << "Number of degrees of freedom: "
+                << dof_handler_u.n_dofs() + dof_handler_p.n_dofs() << " ("
+                << dof_handler_u.n_dofs() << '+' << dof_handler_p.n_dofs()
+                << ')' << std::endl;
+
+        assemble_rhs();
+        solve();
+
+        deallog << std::endl;
+      }
+  }
+} // namespace StokesClass
+
+
+int
+main(int argc, char *argv[])
+{
+  dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
+  mpi_initlog();
+  try
+    {
+      {
+        deallog.push("2d");
+        StokesClass::StokesProblem<2> problem;
+        problem.run();
+        deallog.pop();
+      }
+      {
+        deallog.push("3d");
+        StokesClass::StokesProblem<3> problem;
+        problem.run();
+        deallog.pop();
+      }
+    }
+  catch (const std::exception &exc)
+    {
+      std::cerr << std::endl
+                << std::endl
+                << "----------------------------------------------------"
+                << std::endl;
+      std::cerr << "Exception on processing: " << std::endl
+                << exc.what() << std::endl
+                << "Aborting!" << std::endl
+                << "----------------------------------------------------"
+                << std::endl;
+      throw;
+    }
+  catch (...)
+    {
+      std::cerr << std::endl
+                << std::endl
+                << "----------------------------------------------------"
+                << std::endl;
+      std::cerr << "Unknown exception!" << std::endl
+                << "Aborting!" << std::endl
+                << "----------------------------------------------------"
+                << std::endl;
+      throw;
+    }
+
+  return 0;
+}
diff --git a/tests/multigrid-global-coarsening/stokes_computation.with_lapack=true.with_p4est=true.mpirun=4.output b/tests/multigrid-global-coarsening/stokes_computation.with_lapack=true.with_p4est=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..1f2687b
--- /dev/null
@@ -0,0 +1,19 @@
+
+DEAL:2d::Sinker problem in 2D.
+DEAL:2d::n_sinker: 4       max/min viscosity ratio: 1000.00
+DEAL:2d::
+DEAL:2d::Number of active cells: 1024 (on 6 levels)
+DEAL:2d::Number of degrees of freedom: 9539 (8450+1089)
+DEAL:2d::Solved-in 69 iterations, final residual: 5.58979e-08
+DEAL:2d::
+DEAL:2d::Number of active cells: 4096 (on 7 levels)
+DEAL:2d::Number of degrees of freedom: 37507 (33282+4225)
+DEAL:2d::Solved-in 69 iterations, final residual: 2.58019e-08
+DEAL:2d::
+DEAL:3d::Sinker problem in 3D.
+DEAL:3d::n_sinker: 4       max/min viscosity ratio: 1000.00
+DEAL:3d::
+DEAL:3d::Number of active cells: 512 (on 4 levels)
+DEAL:3d::Number of degrees of freedom: 15468 (14739+729)
+DEAL:3d::Solved-in 62 iterations, final residual: 1.99453e-08
+DEAL:3d::
diff --git a/tests/multigrid-global-coarsening/transfer_05.cc b/tests/multigrid-global-coarsening/transfer_05.cc
new file mode 100644 (file)
index 0000000..75b49c7
--- /dev/null
@@ -0,0 +1,220 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2006 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// check MGTransferBlockMatrixFree::copy_[from|to]_mg by comparison to non-block
+// MGTransferMatrixFree
+
+#include <deal.II/base/function.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/multigrid/mg_constrained_dofs.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <algorithm>
+
+#include "../tests.h"
+
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference non-block
+      MGTransferMF<dim, Number> transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free block transfer
+      MGTransferBlockMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      const unsigned int nb = 3;
+
+      MGLevelObject<LinearAlgebra::distributed::BlockVector<Number>> lbv(
+        0, tr.n_global_levels() - 1);
+      LinearAlgebra::distributed::BlockVector<Number> bv(nb);
+
+      MGLevelObject<LinearAlgebra::distributed::Vector<Number>> lv(
+        0, tr.n_global_levels() - 1);
+      LinearAlgebra::distributed::Vector<Number> v(nb);
+
+      // initialize
+      v.reinit(mgdof.locally_owned_dofs(), MPI_COMM_WORLD);
+      for (unsigned int b = 0; b < nb; ++b)
+        bv.block(b).reinit(mgdof.locally_owned_dofs(), MPI_COMM_WORLD);
+
+      for (unsigned int l = lbv.min_level(); l <= lbv.max_level(); ++l)
+        {
+          lv[l].reinit(mgdof.locally_owned_mg_dofs(l), MPI_COMM_WORLD);
+
+          lbv[l].reinit(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            lbv[l].block(b).reinit(mgdof.locally_owned_mg_dofs(l),
+                                   MPI_COMM_WORLD);
+
+          lbv[l].collect_sizes();
+
+          // set values:
+          for (unsigned int b = 0; b < nb; ++b)
+            for (unsigned int i = 0; i < lbv[l].block(b).locally_owned_size();
+                 ++i)
+              lbv[l].block(b).local_element(i) = random_value<Number>();
+
+          lbv[l].compress(VectorOperation::insert);
+        }
+
+      // check copy_from_mg
+      transfer.copy_from_mg(mgdof, bv, lbv);
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+            lv[l] = lbv[l].block(b);
+
+          transfer_ref.copy_from_mg(mgdof, v, lv);
+          v -= bv.block(b);
+          deallog << "Diff copy_from_mg b" << b << ": " << v.l2_norm()
+                  << std::endl;
+        }
+
+      // check copy_to_mg
+      // use un-initialized level-block vector to make sure that it will be
+      // set correctly in copy_to_mg().
+      MGLevelObject<LinearAlgebra::distributed::BlockVector<Number>> lbv2(
+        0, tr.n_global_levels() - 1);
+      for (unsigned int b = 0; b < nb; ++b)
+        for (unsigned int i = 0; i < bv.block(b).locally_owned_size(); ++i)
+          bv.block(b).local_element(i) = random_value<Number>();
+
+      transfer.copy_to_mg(mgdof, lbv2, bv);
+      // Also check that the block vector has its (global) size set on each
+      // level:
+      for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+        {
+          unsigned int total_size = 0;
+          for (unsigned int b = 0; b < nb; ++b)
+            total_size += lbv2[l].block(b).size();
+
+          AssertThrow(total_size == lbv2[l].size(),
+                      ExcDimensionMismatch(total_size, lbv2[l].size()));
+        }
+
+      // Finally check the difference:
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          v = bv.block(b);
+          transfer_ref.copy_to_mg(mgdof, lv, v);
+          for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+            {
+              lv[l] -= lbv2[l].block(b);
+              deallog << "Diff copy_to_mg   l" << l << ": " << lv[l].l2_norm()
+                      << std::endl;
+            }
+        }
+
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_05.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/transfer_05.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..bace0b4
--- /dev/null
@@ -0,0 +1,367 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_from_mg b2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_06.cc b/tests/multigrid-global-coarsening/transfer_06.cc
new file mode 100644 (file)
index 0000000..b209ca7
--- /dev/null
@@ -0,0 +1,244 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2006 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// check MGTransferBlockMatrixFree::copy_[from|to]_mg by comparison to non-block
+// MGTransferMatrixFree. This is similar to transfer_05 but using
+// a separate DoFHandler for each block
+
+#include <deal.II/base/function.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_accessor.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/tria_iterator.h>
+
+#include <deal.II/multigrid/mg_constrained_dofs.h>
+#include <deal.II/multigrid/mg_tools.h>
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <algorithm>
+
+#include "../tests.h"
+
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  const unsigned int nb = 2;
+
+  FE_Q<dim> fe_1(fe_degree + 1);
+  FE_Q<dim> fe_2(fe_degree);
+
+  deallog << "FE: " << fe_1.get_name() << std::endl;
+  deallog << "FE: " << fe_2.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof_1(tr);
+      mgdof_1.distribute_dofs(fe_1);
+      mgdof_1.distribute_mg_dofs();
+
+      DoFHandler<dim> mgdof_2(tr);
+      mgdof_2.distribute_dofs(fe_2);
+      mgdof_2.distribute_mg_dofs();
+
+      const std::vector<const DoFHandler<dim> *> mgdof_ptr{&mgdof_1, &mgdof_2};
+
+      std::vector<MGConstrainedDoFs> mg_constrained_dofs_vector(2);
+      for (unsigned int i = 0; i < mgdof_ptr.size(); ++i)
+        {
+          mg_constrained_dofs_vector[i].initialize(*mgdof_ptr[i]);
+          mg_constrained_dofs_vector[i].make_zero_boundary_constraints(
+            *mgdof_ptr[i], {0});
+        }
+
+      // build reference non-block
+      std::vector<MGTransferMF<dim, Number>> transfer_ref;
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          transfer_ref.emplace_back(mg_constrained_dofs_vector[b]);
+          transfer_ref[b].build(*mgdof_ptr[b]);
+        }
+
+      // build matrix-free block transfer
+      MGTransferBlockMF<dim, Number> transfer(mg_constrained_dofs_vector);
+      transfer.build(mgdof_ptr);
+
+      MGLevelObject<LinearAlgebra::distributed::BlockVector<Number>> lbv(
+        0, tr.n_global_levels() - 1);
+      LinearAlgebra::distributed::BlockVector<Number> bv(nb);
+
+      MGLevelObject<LinearAlgebra::distributed::Vector<Number>> lv(
+        0, tr.n_global_levels() - 1);
+      LinearAlgebra::distributed::Vector<Number> v(nb);
+
+      // initialize
+      for (unsigned int b = 0; b < nb; ++b)
+        bv.block(b).reinit(mgdof_ptr[b]->locally_owned_dofs(), MPI_COMM_WORLD);
+
+      for (unsigned int l = lbv.min_level(); l <= lbv.max_level(); ++l)
+        {
+          lbv[l].reinit(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            lbv[l].block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(l),
+                                   MPI_COMM_WORLD);
+
+          lbv[l].collect_sizes();
+
+          // set values:
+          for (unsigned int b = 0; b < nb; ++b)
+            for (unsigned int i = 0; i < lbv[l].block(b).locally_owned_size();
+                 ++i)
+              lbv[l].block(b).local_element(i) = random_value<double>();
+
+          lbv[l].compress(VectorOperation::insert);
+        }
+
+      // check copy_from_mg
+      transfer.copy_from_mg(mgdof_ptr, bv, lbv);
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          v.reinit(mgdof_ptr[b]->locally_owned_dofs(), MPI_COMM_WORLD);
+
+          for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+            {
+              lv[l].reinit(mgdof_ptr[b]->locally_owned_mg_dofs(l),
+                           MPI_COMM_WORLD);
+              lv[l] = lbv[l].block(b);
+            }
+
+          transfer_ref[b].copy_from_mg(*mgdof_ptr[b], v, lv);
+          v -= bv.block(b);
+          deallog << "Diff copy_from_mg b" << b << ": " << v.l2_norm()
+                  << std::endl;
+        }
+
+      // check copy_to_mg
+      // use un-initialized level-block vector to make sure that it will be
+      // set correctly in copy_to_mg().
+      MGLevelObject<LinearAlgebra::distributed::BlockVector<Number>> lbv2(
+        0, tr.n_global_levels() - 1);
+      for (unsigned int b = 0; b < nb; ++b)
+        for (unsigned int i = 0; i < bv.block(b).locally_owned_size(); ++i)
+          bv.block(b).local_element(i) = random_value<double>();
+
+      transfer.copy_to_mg(mgdof_ptr, lbv2, bv);
+      // Also check that the block vector has its (global) size set on each
+      // level:
+      for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+        {
+          unsigned int total_size = 0;
+          for (unsigned int b = 0; b < nb; ++b)
+            total_size += lbv2[l].block(b).size();
+
+          AssertThrow(total_size == lbv2[l].size(),
+                      ExcDimensionMismatch(total_size, lbv2[l].size()));
+        }
+
+      // Finally check the difference:
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          v.reinit(mgdof_ptr[b]->locally_owned_dofs(), MPI_COMM_WORLD);
+
+          v = bv.block(b);
+          transfer_ref[b].copy_to_mg(*mgdof_ptr[b], lv, v);
+          for (unsigned int l = lv.min_level(); l <= lv.max_level(); ++l)
+            {
+              lv[l] -= lbv2[l].block(b);
+              deallog << "Diff copy_to_mg   l" << l << ": " << lv[l].l2_norm()
+                      << std::endl;
+            }
+        }
+
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_06.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/transfer_06.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..0a70122
--- /dev/null
@@ -0,0 +1,265 @@
+
+DEAL::FE: FE_Q<2>(2)
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(4)
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(4)
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff copy_from_mg b0: 0.00000
+DEAL::Diff copy_from_mg b1: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::Diff copy_to_mg   l0: 0.00000
+DEAL::Diff copy_to_mg   l1: 0.00000
+DEAL::Diff copy_to_mg   l2: 0.00000
+DEAL::Diff copy_to_mg   l3: 0.00000
+DEAL::Diff copy_to_mg   l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_01.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_01.cc
new file mode 100644 (file)
index 0000000..7932704
--- /dev/null
@@ -0,0 +1,151 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with uniform meshes for FE_Q
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3, 4, 5, 6, 8};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=1.output b/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..17444f6
--- /dev/null
@@ -0,0 +1,364 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 2.22045e-16
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.57009e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 5.43896e-16
+DEAL::Diff restrict add l3: 4.44089e-16
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 1.11022e-16
+DEAL::Diff prolongate   l2: 1.66533e-16
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 9.93014e-16
+DEAL::Diff restrict add l2: 1.17495e-15
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.11022e-16
+DEAL::Diff prolongate   l4: 2.77556e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 8.30815e-16
+DEAL::Diff restrict add l3: 7.69185e-16
+DEAL::Diff restrict     l4: 2.09476e-15
+DEAL::Diff restrict add l4: 2.22045e-15
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 1.57009e-16
+DEAL::Diff prolongate   l2: 3.05311e-16
+DEAL::Diff restrict     l1: 1.29473e-15
+DEAL::Diff restrict add l1: 1.40433e-15
+DEAL::Diff restrict     l2: 2.14132e-15
+DEAL::Diff restrict add l2: 2.43238e-15
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 1.11022e-16
+DEAL::Diff prolongate   l2: 2.54384e-16
+DEAL::Diff prolongate   l3: 4.75099e-16
+DEAL::Diff restrict     l1: 4.96507e-16
+DEAL::Diff restrict add l1: 4.44089e-16
+DEAL::Diff restrict     l2: 1.15378e-15
+DEAL::Diff restrict add l2: 1.25607e-15
+DEAL::Diff restrict     l3: 3.16560e-15
+DEAL::Diff restrict add l3: 3.35280e-15
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.11022e-16
+DEAL::Diff prolongate   l4: 1.57009e-16
+DEAL::Diff prolongate   l5: 6.52699e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 9.67870e-16
+DEAL::Diff restrict add l3: 9.93014e-16
+DEAL::Diff restrict     l4: 1.55431e-15
+DEAL::Diff restrict add l4: 1.67640e-15
+DEAL::Diff restrict     l5: 4.09129e-15
+DEAL::Diff restrict add l5: 4.49606e-15
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 4.80741e-16
+DEAL::Diff restrict     l1: 9.15513e-16
+DEAL::Diff restrict add l1: 9.93014e-16
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 1.86190e-16
+DEAL::Diff prolongate   l2: 8.36002e-16
+DEAL::Diff restrict     l1: 1.88411e-15
+DEAL::Diff restrict add l1: 1.77636e-15
+DEAL::Diff restrict     l2: 1.75542e-15
+DEAL::Diff restrict add l2: 2.23152e-15
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 1.43538e-15
+DEAL::Diff restrict     l1: 3.89726e-15
+DEAL::Diff restrict add l1: 4.47958e-15
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 2.92423e-16
+DEAL::Diff prolongate   l2: 8.77050e-16
+DEAL::Diff prolongate   l3: 1.86878e-15
+DEAL::Diff restrict     l1: 7.69185e-16
+DEAL::Diff restrict add l1: 7.69185e-16
+DEAL::Diff restrict     l2: 1.77982e-15
+DEAL::Diff restrict add l2: 1.71995e-15
+DEAL::Diff restrict     l3: 5.40828e-15
+DEAL::Diff restrict add l3: 5.59094e-15
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 2.17853e-15
+DEAL::Diff restrict     l1: 6.14936e-15
+DEAL::Diff restrict add l1: 6.60186e-15
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 1.47799e-15
+DEAL::Diff prolongate   l2: 2.65352e-15
+DEAL::Diff restrict     l1: 3.82826e-15
+DEAL::Diff restrict add l1: 3.82665e-15
+DEAL::Diff restrict     l2: 7.88395e-15
+DEAL::Diff restrict add l2: 8.71649e-15
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 2.74525e-16
+DEAL::Diff prolongate   l2: 7.76201e-16
+DEAL::Diff prolongate   l3: 1.72781e-15
+DEAL::Diff prolongate   l4: 3.59470e-15
+DEAL::Diff restrict     l1: 3.14018e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 2.57035e-15
+DEAL::Diff restrict add l2: 2.62727e-15
+DEAL::Diff restrict     l3: 5.33312e-15
+DEAL::Diff restrict add l3: 5.73030e-15
+DEAL::Diff restrict     l4: 1.11508e-14
+DEAL::Diff restrict add l4: 1.20581e-14
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 8.88178e-16
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 2.83052e-16
+DEAL::Diff restrict     l1: 2.51215e-15
+DEAL::Diff restrict add l1: 2.51215e-15
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.11022e-16
+DEAL::Diff prolongate   l3: 4.87516e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 2.62727e-15
+DEAL::Diff restrict add l3: 3.07674e-15
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 7.53533e-16
+DEAL::Diff restrict     l1: 5.10220e-15
+DEAL::Diff restrict add l1: 5.61733e-15
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 2.23773e-16
+DEAL::Diff prolongate   l2: 1.17095e-15
+DEAL::Diff restrict     l1: 1.40433e-15
+DEAL::Diff restrict add l1: 1.53837e-15
+DEAL::Diff restrict     l2: 8.10387e-15
+DEAL::Diff restrict add l2: 8.54223e-15
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 3.76063e-16
+DEAL::Diff prolongate   l4: 1.91920e-15
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 4.84444e-15
+DEAL::Diff restrict add l3: 4.94517e-15
+DEAL::Diff restrict     l4: 1.43214e-14
+DEAL::Diff restrict add l4: 1.52161e-14
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 5.85228e-16
+DEAL::Diff restrict     l1: 4.16593e-15
+DEAL::Diff restrict add l1: 4.78299e-15
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 1.18099e-15
+DEAL::Diff prolongate   l2: 3.22757e-15
+DEAL::Diff restrict     l1: 4.86475e-15
+DEAL::Diff restrict add l1: 5.10220e-15
+DEAL::Diff restrict     l2: 2.45879e-14
+DEAL::Diff restrict add l2: 2.53986e-14
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 6.65254e-15
+DEAL::Diff restrict     l1: 4.35629e-14
+DEAL::Diff restrict add l1: 4.43806e-14
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 5.45722e-16
+DEAL::Diff prolongate   l2: 3.47491e-15
+DEAL::Diff prolongate   l3: 1.08273e-14
+DEAL::Diff restrict     l1: 9.18739e-15
+DEAL::Diff restrict add l1: 1.02044e-14
+DEAL::Diff restrict     l2: 2.49877e-14
+DEAL::Diff restrict add l2: 2.48888e-14
+DEAL::Diff restrict     l3: 7.50329e-14
+DEAL::Diff restrict add l3: 7.66746e-14
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 3.72529e-08
+DEAL::Diff prolongate   l2: 1.31933e-07
+DEAL::Diff restrict     l1: 1.67638e-08
+DEAL::Diff restrict add l1: 1.67638e-08
+DEAL::Diff restrict     l2: 2.42676e-07
+DEAL::Diff restrict add l2: 4.47664e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 1.49012e-08
+DEAL::Diff prolongate   l2: 1.44994e-07
+DEAL::Diff prolongate   l3: 3.16323e-07
+DEAL::Diff restrict     l1: 9.87202e-08
+DEAL::Diff restrict add l1: 9.87202e-08
+DEAL::Diff restrict     l2: 2.15219e-07
+DEAL::Diff restrict add l2: 2.62683e-07
+DEAL::Diff restrict     l3: 8.19761e-07
+DEAL::Diff restrict add l3: 8.79582e-07
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 2.98754e-07
+DEAL::Diff prolongate   l2: 4.70776e-07
+DEAL::Diff restrict     l1: 4.57351e-07
+DEAL::Diff restrict add l1: 8.03906e-07
+DEAL::Diff restrict     l2: 1.05171e-06
+DEAL::Diff restrict add l2: 1.45557e-06
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 4.77070e-08
+DEAL::Diff prolongate   l2: 8.87839e-08
+DEAL::Diff prolongate   l3: 3.12393e-07
+DEAL::Diff prolongate   l4: 6.85456e-07
+DEAL::Diff restrict     l1: 2.84053e-08
+DEAL::Diff restrict add l1: 2.84053e-08
+DEAL::Diff restrict     l2: 3.84794e-07
+DEAL::Diff restrict add l2: 4.83101e-07
+DEAL::Diff restrict     l3: 7.28061e-07
+DEAL::Diff restrict add l3: 9.02211e-07
+DEAL::Diff restrict     l4: 1.41847e-06
+DEAL::Diff restrict add l4: 1.74159e-06
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 4.30708e-07
+DEAL::Diff prolongate   l2: 9.62514e-07
+DEAL::Diff restrict     l1: 1.03503e-06
+DEAL::Diff restrict add l1: 1.12037e-06
+DEAL::Diff restrict     l2: 1.90372e-06
+DEAL::Diff restrict add l2: 2.24836e-06
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 2.37561e-07
+DEAL::Diff prolongate   l2: 4.85227e-07
+DEAL::Diff prolongate   l3: 9.86324e-07
+DEAL::Diff restrict     l1: 4.79749e-07
+DEAL::Diff restrict add l1: 7.42761e-07
+DEAL::Diff restrict     l2: 1.10715e-06
+DEAL::Diff restrict add l2: 1.46215e-06
+DEAL::Diff restrict     l3: 2.22257e-06
+DEAL::Diff restrict add l3: 2.53551e-06
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 1.49012e-08
+DEAL::Diff prolongate   l2: 1.16789e-07
+DEAL::Diff prolongate   l3: 3.15373e-07
+DEAL::Diff prolongate   l4: 7.29600e-07
+DEAL::Diff prolongate   l5: 1.41394e-06
+DEAL::Diff restrict     l1: 2.45869e-07
+DEAL::Diff restrict add l1: 2.45869e-07
+DEAL::Diff restrict     l2: 4.01137e-07
+DEAL::Diff restrict add l2: 4.01137e-07
+DEAL::Diff restrict     l3: 6.86101e-07
+DEAL::Diff restrict add l3: 7.81855e-07
+DEAL::Diff restrict     l4: 1.39585e-06
+DEAL::Diff restrict add l4: 1.79306e-06
+DEAL::Diff restrict     l5: 3.06809e-06
+DEAL::Diff restrict add l5: 3.72838e-06
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 1.09627e-07
+DEAL::Diff restrict     l1: 5.44882e-07
+DEAL::Diff restrict add l1: 5.44882e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 5.32529e-09
+DEAL::Diff prolongate   l2: 3.39210e-07
+DEAL::Diff restrict     l1: 3.74159e-07
+DEAL::Diff restrict add l1: 3.74159e-07
+DEAL::Diff restrict     l2: 1.15370e-06
+DEAL::Diff restrict add l2: 1.22900e-06
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 8.62651e-07
+DEAL::Diff restrict     l1: 2.89970e-06
+DEAL::Diff restrict add l1: 3.35540e-06
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 1.39089e-07
+DEAL::Diff prolongate   l2: 3.04131e-07
+DEAL::Diff prolongate   l3: 1.38532e-06
+DEAL::Diff restrict     l1: 6.78934e-07
+DEAL::Diff restrict add l1: 6.78934e-07
+DEAL::Diff restrict     l2: 1.38175e-06
+DEAL::Diff restrict add l2: 1.35441e-06
+DEAL::Diff restrict     l3: 4.35419e-06
+DEAL::Diff restrict add l3: 4.60971e-06
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 2.07245e-06
+DEAL::Diff restrict     l1: 5.91522e-06
+DEAL::Diff restrict add l1: 6.32888e-06
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 7.71899e-07
+DEAL::Diff prolongate   l2: 2.83835e-06
+DEAL::Diff restrict     l1: 2.59603e-06
+DEAL::Diff restrict add l1: 2.87564e-06
+DEAL::Diff restrict     l2: 7.95574e-06
+DEAL::Diff restrict add l2: 8.72324e-06
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 5.82505e-08
+DEAL::Diff prolongate   l2: 4.03345e-07
+DEAL::Diff prolongate   l3: 1.32056e-06
+DEAL::Diff prolongate   l4: 4.47191e-06
+DEAL::Diff restrict     l1: 3.57279e-07
+DEAL::Diff restrict add l1: 3.57279e-07
+DEAL::Diff restrict     l2: 1.26665e-06
+DEAL::Diff restrict add l2: 1.64848e-06
+DEAL::Diff restrict     l3: 4.01036e-06
+DEAL::Diff restrict add l3: 4.09562e-06
+DEAL::Diff restrict     l4: 1.25440e-05
+DEAL::Diff restrict add l4: 1.38985e-05
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=4.output b/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..f3a370d
--- /dev/null
@@ -0,0 +1,364 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.57009e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 2.22045e-16
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 6.66134e-16
+DEAL::Diff restrict add l3: 7.69185e-16
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 4.44089e-16
+DEAL::Diff restrict add l1: 4.44089e-16
+DEAL::Diff restrict     l2: 1.29473e-15
+DEAL::Diff restrict add l2: 1.40433e-15
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 5.55112e-17
+DEAL::Diff prolongate   l4: 2.43554e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 5.87475e-16
+DEAL::Diff restrict add l3: 4.44089e-16
+DEAL::Diff restrict     l4: 1.33227e-15
+DEAL::Diff restrict add l4: 1.47288e-15
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 3.76495e-16
+DEAL::Diff restrict     l1: 1.17495e-15
+DEAL::Diff restrict add l1: 1.17495e-15
+DEAL::Diff restrict     l2: 2.14132e-15
+DEAL::Diff restrict add l2: 2.39149e-15
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 2.41967e-16
+DEAL::Diff prolongate   l3: 4.51828e-16
+DEAL::Diff restrict     l1: 2.22045e-16
+DEAL::Diff restrict add l1: 4.44089e-16
+DEAL::Diff restrict     l2: 1.48952e-15
+DEAL::Diff restrict add l2: 1.53837e-15
+DEAL::Diff restrict     l3: 2.44249e-15
+DEAL::Diff restrict add l3: 2.80867e-15
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.24127e-16
+DEAL::Diff prolongate   l4: 2.67665e-16
+DEAL::Diff prolongate   l5: 4.95730e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 7.02167e-16
+DEAL::Diff restrict add l3: 6.28037e-16
+DEAL::Diff restrict     l4: 1.52226e-15
+DEAL::Diff restrict add l4: 1.88411e-15
+DEAL::Diff restrict     l5: 3.75019e-15
+DEAL::Diff restrict add l5: 3.99680e-15
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 5.35510e-16
+DEAL::Diff restrict     l1: 1.53837e-15
+DEAL::Diff restrict add l1: 1.53837e-15
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 2.77902e-16
+DEAL::Diff prolongate   l2: 1.02023e-15
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 4.44089e-16
+DEAL::Diff restrict     l2: 2.63897e-15
+DEAL::Diff restrict add l2: 2.80867e-15
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 1.47011e-15
+DEAL::Diff restrict     l1: 3.83198e-15
+DEAL::Diff restrict add l1: 4.01526e-15
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 3.87586e-16
+DEAL::Diff prolongate   l2: 8.10619e-16
+DEAL::Diff prolongate   l3: 1.77724e-15
+DEAL::Diff restrict     l1: 7.69185e-16
+DEAL::Diff restrict add l1: 1.08779e-15
+DEAL::Diff restrict     l2: 1.76940e-15
+DEAL::Diff restrict add l2: 1.83103e-15
+DEAL::Diff restrict     l3: 5.45198e-15
+DEAL::Diff restrict add l3: 5.51547e-15
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 2.43957e-15
+DEAL::Diff restrict     l1: 6.58340e-15
+DEAL::Diff restrict add l1: 7.00409e-15
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 1.52511e-15
+DEAL::Diff prolongate   l2: 2.75500e-15
+DEAL::Diff restrict     l1: 2.71778e-15
+DEAL::Diff restrict add l1: 3.13232e-15
+DEAL::Diff restrict     l2: 7.50219e-15
+DEAL::Diff restrict add l2: 8.11603e-15
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 5.32625e-16
+DEAL::Diff prolongate   l2: 1.03306e-15
+DEAL::Diff prolongate   l3: 1.87470e-15
+DEAL::Diff prolongate   l4: 3.84816e-15
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 2.07704e-15
+DEAL::Diff restrict add l2: 2.66454e-15
+DEAL::Diff restrict     l3: 4.96856e-15
+DEAL::Diff restrict add l3: 5.31517e-15
+DEAL::Diff restrict     l4: 1.11741e-14
+DEAL::Diff restrict add l4: 1.19415e-14
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 1.66533e-16
+DEAL::Diff restrict     l1: 1.60119e-15
+DEAL::Diff restrict add l1: 1.83103e-15
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 3.11884e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 3.46845e-15
+DEAL::Diff restrict add l3: 3.87148e-15
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 5.17215e-16
+DEAL::Diff restrict     l1: 4.86475e-15
+DEAL::Diff restrict add l1: 5.29193e-15
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 2.14994e-16
+DEAL::Diff prolongate   l2: 9.84663e-16
+DEAL::Diff restrict     l1: 1.53837e-15
+DEAL::Diff restrict add l1: 1.53837e-15
+DEAL::Diff restrict     l2: 6.76417e-15
+DEAL::Diff restrict add l2: 7.29713e-15
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 3.52521e-16
+DEAL::Diff prolongate   l4: 1.77530e-15
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 3.74196e-15
+DEAL::Diff restrict add l3: 3.97205e-15
+DEAL::Diff restrict     l4: 1.30912e-14
+DEAL::Diff restrict add l4: 1.43901e-14
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 7.61858e-16
+DEAL::Diff restrict     l1: 1.06951e-14
+DEAL::Diff restrict add l1: 1.06951e-14
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 6.76681e-16
+DEAL::Diff prolongate   l2: 3.94720e-15
+DEAL::Diff restrict     l1: 3.66205e-15
+DEAL::Diff restrict add l1: 3.20237e-15
+DEAL::Diff restrict     l2: 2.23362e-14
+DEAL::Diff restrict add l2: 2.30199e-14
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 8.06498e-15
+DEAL::Diff restrict     l1: 4.17135e-14
+DEAL::Diff restrict add l1: 4.21809e-14
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 7.45673e-16
+DEAL::Diff prolongate   l2: 4.05889e-15
+DEAL::Diff prolongate   l3: 1.18902e-14
+DEAL::Diff restrict     l1: 3.55271e-15
+DEAL::Diff restrict add l1: 3.43990e-15
+DEAL::Diff restrict     l2: 2.10627e-14
+DEAL::Diff restrict add l2: 2.12329e-14
+DEAL::Diff restrict     l3: 7.30222e-14
+DEAL::Diff restrict add l3: 7.41273e-14
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 2.98023e-08
+DEAL::Diff prolongate   l2: 1.17073e-07
+DEAL::Diff restrict     l1: 1.09896e-07
+DEAL::Diff restrict add l1: 1.09896e-07
+DEAL::Diff restrict     l2: 2.72120e-07
+DEAL::Diff restrict add l2: 3.19417e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 1.86265e-08
+DEAL::Diff prolongate   l2: 8.98385e-08
+DEAL::Diff prolongate   l3: 2.91263e-07
+DEAL::Diff restrict     l1: 2.09548e-08
+DEAL::Diff restrict add l1: 2.59373e-07
+DEAL::Diff restrict     l2: 2.81788e-07
+DEAL::Diff restrict add l2: 2.43079e-07
+DEAL::Diff restrict     l3: 6.86195e-07
+DEAL::Diff restrict add l3: 9.19423e-07
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 2.10869e-07
+DEAL::Diff prolongate   l2: 5.18665e-07
+DEAL::Diff restrict     l1: 5.39228e-07
+DEAL::Diff restrict add l1: 6.22714e-07
+DEAL::Diff restrict     l2: 1.05092e-06
+DEAL::Diff restrict add l2: 1.28920e-06
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 2.32831e-09
+DEAL::Diff prolongate   l2: 1.06222e-07
+DEAL::Diff prolongate   l3: 3.08336e-07
+DEAL::Diff prolongate   l4: 6.35164e-07
+DEAL::Diff restrict     l1: 9.77889e-08
+DEAL::Diff restrict add l1: 9.77889e-08
+DEAL::Diff restrict     l2: 3.48858e-07
+DEAL::Diff restrict add l2: 4.43091e-07
+DEAL::Diff restrict     l3: 6.32397e-07
+DEAL::Diff restrict add l3: 6.36345e-07
+DEAL::Diff restrict     l4: 1.34609e-06
+DEAL::Diff restrict add l4: 1.74577e-06
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 4.65403e-07
+DEAL::Diff prolongate   l2: 8.14610e-07
+DEAL::Diff restrict     l1: 8.38442e-07
+DEAL::Diff restrict add l1: 1.04497e-06
+DEAL::Diff restrict     l2: 1.93553e-06
+DEAL::Diff restrict add l2: 2.22941e-06
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 1.92120e-07
+DEAL::Diff prolongate   l2: 4.89637e-07
+DEAL::Diff prolongate   l3: 1.00159e-06
+DEAL::Diff restrict     l1: 4.66622e-07
+DEAL::Diff restrict add l1: 6.18348e-07
+DEAL::Diff restrict     l2: 1.07663e-06
+DEAL::Diff restrict add l2: 1.25560e-06
+DEAL::Diff restrict     l3: 2.27705e-06
+DEAL::Diff restrict add l3: 2.76853e-06
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 1.86265e-08
+DEAL::Diff prolongate   l2: 1.34182e-07
+DEAL::Diff prolongate   l3: 2.50837e-07
+DEAL::Diff prolongate   l4: 6.39631e-07
+DEAL::Diff prolongate   l5: 1.36606e-06
+DEAL::Diff restrict     l1: 1.41561e-07
+DEAL::Diff restrict add l1: 1.41561e-07
+DEAL::Diff restrict     l2: 2.95878e-07
+DEAL::Diff restrict add l2: 3.03793e-07
+DEAL::Diff restrict     l3: 7.65107e-07
+DEAL::Diff restrict add l3: 8.77487e-07
+DEAL::Diff restrict     l4: 1.37239e-06
+DEAL::Diff restrict add l4: 1.69515e-06
+DEAL::Diff restrict     l5: 2.90070e-06
+DEAL::Diff restrict add l5: 3.56294e-06
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 3.16376e-08
+DEAL::Diff restrict     l1: 1.28523e-07
+DEAL::Diff restrict add l1: 6.05360e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 1.12532e-08
+DEAL::Diff prolongate   l2: 3.87787e-07
+DEAL::Diff restrict     l1: 6.46105e-08
+DEAL::Diff restrict add l1: 6.46105e-08
+DEAL::Diff restrict     l2: 1.24234e-06
+DEAL::Diff restrict add l2: 1.24808e-06
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 8.05794e-07
+DEAL::Diff restrict     l1: 2.83397e-06
+DEAL::Diff restrict add l1: 3.05075e-06
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 2.11658e-08
+DEAL::Diff prolongate   l2: 3.90292e-07
+DEAL::Diff prolongate   l3: 1.51881e-06
+DEAL::Diff restrict     l1: 4.28758e-07
+DEAL::Diff restrict add l1: 4.28758e-07
+DEAL::Diff restrict     l2: 1.01649e-06
+DEAL::Diff restrict add l2: 1.14211e-06
+DEAL::Diff restrict     l3: 3.94122e-06
+DEAL::Diff restrict add l3: 4.23609e-06
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 2.14713e-06
+DEAL::Diff restrict     l1: 6.15121e-06
+DEAL::Diff restrict add l1: 6.59074e-06
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 9.90071e-07
+DEAL::Diff prolongate   l2: 2.90218e-06
+DEAL::Diff restrict     l1: 3.04764e-06
+DEAL::Diff restrict add l1: 3.40151e-06
+DEAL::Diff restrict     l2: 7.91521e-06
+DEAL::Diff restrict add l2: 8.68910e-06
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 1.73861e-08
+DEAL::Diff prolongate   l2: 4.86459e-07
+DEAL::Diff prolongate   l3: 1.41420e-06
+DEAL::Diff prolongate   l4: 4.47432e-06
+DEAL::Diff restrict     l1: 4.23752e-08
+DEAL::Diff restrict add l1: 4.34462e-07
+DEAL::Diff restrict     l2: 1.49430e-06
+DEAL::Diff restrict add l2: 1.49275e-06
+DEAL::Diff restrict     l3: 4.52097e-06
+DEAL::Diff restrict add l3: 4.93599e-06
+DEAL::Diff restrict     l4: 1.26332e-05
+DEAL::Diff restrict add l4: 1.38610e-05
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=7.output b/tests/multigrid-global-coarsening/transfer_matrix_free_01.with_p4est=true.with_trilinos=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..57c8077
--- /dev/null
@@ -0,0 +1,364 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.11022e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 6.28037e-16
+DEAL::Diff restrict add l3: 7.69185e-16
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.57009e-16
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 9.42055e-16
+DEAL::Diff restrict add l2: 8.88178e-16
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 2.73361e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 7.77156e-16
+DEAL::Diff restrict add l3: 8.00593e-16
+DEAL::Diff restrict     l4: 1.29473e-15
+DEAL::Diff restrict add l4: 1.66163e-15
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 1.11022e-16
+DEAL::Diff prolongate   l2: 3.46945e-16
+DEAL::Diff restrict     l1: 8.00593e-16
+DEAL::Diff restrict add l1: 9.93014e-16
+DEAL::Diff restrict     l2: 2.36037e-15
+DEAL::Diff restrict add l2: 2.58946e-15
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 9.61481e-17
+DEAL::Diff prolongate   l3: 4.83935e-16
+DEAL::Diff restrict     l1: 6.66134e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 9.42055e-16
+DEAL::Diff restrict add l2: 1.17495e-15
+DEAL::Diff restrict     l3: 2.48253e-15
+DEAL::Diff restrict add l3: 2.73755e-15
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 5.55112e-17
+DEAL::Diff prolongate   l4: 1.57009e-16
+DEAL::Diff prolongate   l5: 5.14040e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 4.96507e-16
+DEAL::Diff restrict add l3: 6.28037e-16
+DEAL::Diff restrict     l4: 1.70917e-15
+DEAL::Diff restrict add l4: 1.89715e-15
+DEAL::Diff restrict     l5: 3.90950e-15
+DEAL::Diff restrict add l5: 4.28264e-15
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 5.86162e-16
+DEAL::Diff restrict     l1: 1.08779e-15
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 4.39840e-16
+DEAL::Diff prolongate   l2: 1.33460e-15
+DEAL::Diff restrict     l1: 4.44089e-16
+DEAL::Diff restrict add l1: 4.44089e-16
+DEAL::Diff restrict     l2: 2.37079e-15
+DEAL::Diff restrict add l2: 2.47258e-15
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 1.30473e-15
+DEAL::Diff restrict     l1: 3.36198e-15
+DEAL::Diff restrict add l1: 3.78128e-15
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 1.57927e-16
+DEAL::Diff prolongate   l2: 8.20434e-16
+DEAL::Diff prolongate   l3: 2.02790e-15
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 8.88178e-16
+DEAL::Diff restrict     l2: 1.15911e-15
+DEAL::Diff restrict add l2: 1.08779e-15
+DEAL::Diff restrict     l3: 4.45440e-15
+DEAL::Diff restrict add l3: 4.48508e-15
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 2.50604e-15
+DEAL::Diff restrict     l1: 5.30560e-15
+DEAL::Diff restrict add l1: 6.22913e-15
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 1.35942e-15
+DEAL::Diff prolongate   l2: 3.05918e-15
+DEAL::Diff restrict     l1: 3.54664e-15
+DEAL::Diff restrict add l1: 4.52339e-15
+DEAL::Diff restrict     l2: 7.68849e-15
+DEAL::Diff restrict add l2: 8.53356e-15
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 4.25711e-16
+DEAL::Diff prolongate   l2: 7.75419e-16
+DEAL::Diff prolongate   l3: 1.72716e-15
+DEAL::Diff prolongate   l4: 3.94909e-15
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 9.93014e-16
+DEAL::Diff restrict     l2: 1.25607e-15
+DEAL::Diff restrict add l2: 1.71995e-15
+DEAL::Diff restrict     l3: 4.36857e-15
+DEAL::Diff restrict add l3: 4.64705e-15
+DEAL::Diff restrict     l4: 1.06615e-14
+DEAL::Diff restrict add l4: 1.15035e-14
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 1.66678e-16
+DEAL::Diff restrict     l1: 1.17495e-15
+DEAL::Diff restrict add l1: 8.88178e-16
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 5.55112e-17
+DEAL::Diff prolongate   l3: 3.80818e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 3.01196e-15
+DEAL::Diff restrict add l3: 3.32326e-15
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 5.62008e-16
+DEAL::Diff restrict     l1: 4.35117e-15
+DEAL::Diff restrict add l1: 4.44089e-15
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 9.71445e-17
+DEAL::Diff prolongate   l2: 1.03975e-15
+DEAL::Diff restrict     l1: 9.93014e-16
+DEAL::Diff restrict add l1: 1.25607e-15
+DEAL::Diff restrict     l2: 6.21725e-15
+DEAL::Diff restrict add l2: 6.73495e-15
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 3.42475e-16
+DEAL::Diff prolongate   l4: 1.72594e-15
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 2.43238e-15
+DEAL::Diff restrict add l3: 2.34990e-15
+DEAL::Diff restrict     l4: 1.14348e-14
+DEAL::Diff restrict add l4: 1.23310e-14
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 6.50327e-16
+DEAL::Diff restrict     l1: 6.08904e-15
+DEAL::Diff restrict add l1: 6.02392e-15
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 9.68541e-16
+DEAL::Diff prolongate   l2: 4.87552e-15
+DEAL::Diff restrict     l1: 4.44089e-15
+DEAL::Diff restrict add l1: 4.52884e-15
+DEAL::Diff restrict     l2: 2.01905e-14
+DEAL::Diff restrict add l2: 2.02986e-14
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 8.78343e-15
+DEAL::Diff restrict     l1: 3.92368e-14
+DEAL::Diff restrict add l1: 3.96547e-14
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 8.84649e-16
+DEAL::Diff prolongate   l2: 3.96858e-15
+DEAL::Diff prolongate   l3: 1.31313e-14
+DEAL::Diff restrict     l1: 2.17558e-15
+DEAL::Diff restrict add l1: 2.17558e-15
+DEAL::Diff restrict     l2: 1.66037e-14
+DEAL::Diff restrict add l2: 1.69294e-14
+DEAL::Diff restrict     l3: 6.69581e-14
+DEAL::Diff restrict add l3: 6.79718e-14
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 3.72529e-08
+DEAL::Diff prolongate   l2: 1.23918e-07
+DEAL::Diff restrict     l1: 1.97440e-07
+DEAL::Diff restrict add l1: 1.97440e-07
+DEAL::Diff restrict     l2: 3.51720e-07
+DEAL::Diff restrict add l2: 4.38541e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 3.72529e-09
+DEAL::Diff prolongate   l2: 1.31323e-07
+DEAL::Diff prolongate   l3: 2.69264e-07
+DEAL::Diff restrict     l1: 3.37139e-07
+DEAL::Diff restrict add l1: 9.87202e-08
+DEAL::Diff restrict     l2: 4.04329e-07
+DEAL::Diff restrict add l2: 3.87504e-07
+DEAL::Diff restrict     l3: 6.87816e-07
+DEAL::Diff restrict add l3: 8.68312e-07
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 2.07089e-07
+DEAL::Diff prolongate   l2: 5.55799e-07
+DEAL::Diff restrict     l1: 5.67399e-07
+DEAL::Diff restrict add l1: 7.86516e-07
+DEAL::Diff restrict     l2: 1.29939e-06
+DEAL::Diff restrict add l2: 1.57817e-06
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 1.19267e-08
+DEAL::Diff prolongate   l2: 1.39742e-07
+DEAL::Diff prolongate   l3: 3.09723e-07
+DEAL::Diff prolongate   l4: 6.63463e-07
+DEAL::Diff restrict     l1: 3.07336e-08
+DEAL::Diff restrict add l1: 3.07336e-08
+DEAL::Diff restrict     l2: 1.83328e-07
+DEAL::Diff restrict add l2: 2.05324e-07
+DEAL::Diff restrict     l3: 6.59020e-07
+DEAL::Diff restrict add l3: 8.18489e-07
+DEAL::Diff restrict     l4: 1.44435e-06
+DEAL::Diff restrict add l4: 1.85608e-06
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 4.05180e-07
+DEAL::Diff prolongate   l2: 8.54370e-07
+DEAL::Diff restrict     l1: 9.93212e-07
+DEAL::Diff restrict add l1: 1.14004e-06
+DEAL::Diff restrict     l2: 1.74876e-06
+DEAL::Diff restrict add l2: 2.16962e-06
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 1.74155e-07
+DEAL::Diff prolongate   l2: 5.19866e-07
+DEAL::Diff prolongate   l3: 9.61759e-07
+DEAL::Diff restrict     l1: 3.23313e-07
+DEAL::Diff restrict add l1: 4.09015e-07
+DEAL::Diff restrict     l2: 1.06199e-06
+DEAL::Diff restrict add l2: 1.32974e-06
+DEAL::Diff restrict     l3: 2.21171e-06
+DEAL::Diff restrict add l3: 2.64991e-06
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.24189e-07
+DEAL::Diff prolongate   l3: 2.63914e-07
+DEAL::Diff prolongate   l4: 6.15720e-07
+DEAL::Diff prolongate   l5: 1.36740e-06
+DEAL::Diff restrict     l1: 1.08965e-07
+DEAL::Diff restrict add l1: 1.08965e-07
+DEAL::Diff restrict     l2: 2.46043e-07
+DEAL::Diff restrict add l2: 3.26259e-07
+DEAL::Diff restrict     l3: 7.10773e-07
+DEAL::Diff restrict add l3: 7.74864e-07
+DEAL::Diff restrict     l4: 1.38466e-06
+DEAL::Diff restrict add l4: 1.63680e-06
+DEAL::Diff restrict     l5: 2.98024e-06
+DEAL::Diff restrict add l5: 3.66432e-06
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 1.39089e-07
+DEAL::Diff restrict     l1: 3.51210e-07
+DEAL::Diff restrict add l1: 3.51210e-07
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 5.32730e-08
+DEAL::Diff prolongate   l2: 3.47201e-07
+DEAL::Diff restrict     l1: 2.75424e-07
+DEAL::Diff restrict add l1: 2.75424e-07
+DEAL::Diff restrict     l2: 1.37599e-06
+DEAL::Diff restrict add l2: 1.65391e-06
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 8.13494e-07
+DEAL::Diff restrict     l1: 2.76829e-06
+DEAL::Diff restrict add l1: 3.07971e-06
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 5.82505e-08
+DEAL::Diff prolongate   l2: 5.17285e-07
+DEAL::Diff prolongate   l3: 1.42520e-06
+DEAL::Diff restrict     l1: 1.60479e-07
+DEAL::Diff restrict add l1: 1.60479e-07
+DEAL::Diff restrict     l2: 1.21423e-06
+DEAL::Diff restrict add l2: 1.45209e-06
+DEAL::Diff restrict     l3: 4.13711e-06
+DEAL::Diff restrict add l3: 4.50632e-06
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 2.05461e-06
+DEAL::Diff restrict     l1: 6.41987e-06
+DEAL::Diff restrict add l1: 7.01234e-06
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 7.72673e-07
+DEAL::Diff prolongate   l2: 2.80277e-06
+DEAL::Diff restrict     l1: 2.64256e-06
+DEAL::Diff restrict add l1: 3.00814e-06
+DEAL::Diff restrict     l2: 8.18270e-06
+DEAL::Diff restrict add l2: 8.99079e-06
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 1.40781e-08
+DEAL::Diff prolongate   l2: 3.60453e-07
+DEAL::Diff prolongate   l3: 1.41714e-06
+DEAL::Diff prolongate   l4: 4.48438e-06
+DEAL::Diff restrict     l1: 2.01369e-07
+DEAL::Diff restrict add l1: 2.01369e-07
+DEAL::Diff restrict     l2: 1.42552e-06
+DEAL::Diff restrict add l2: 1.66821e-06
+DEAL::Diff restrict     l3: 4.00370e-06
+DEAL::Diff restrict add l3: 4.28661e-06
+DEAL::Diff restrict     l4: 1.28845e-05
+DEAL::Diff restrict add l4: 1.39500e-05
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_02.cc
new file mode 100644 (file)
index 0000000..e6205aa
--- /dev/null
@@ -0,0 +1,180 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with adaptive meshes for FE_Q
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=1.output b/tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..2554643
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 5.55112e-17
+DEAL::Diff prolongate   l4: 1.46869e-16
+DEAL::Diff prolongate   l5: 1.57009e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 1.06489e-15
+DEAL::Diff restrict add l3: 1.08779e-15
+DEAL::Diff restrict     l4: 6.28037e-16
+DEAL::Diff restrict add l4: 6.28037e-16
+DEAL::Diff restrict     l5: 5.43896e-16
+DEAL::Diff restrict add l5: 7.69185e-16
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 7.85046e-17
+DEAL::Diff prolongate   l4: 1.66533e-16
+DEAL::Diff prolongate   l5: 2.41967e-16
+DEAL::Diff prolongate   l6: 3.92523e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 9.42055e-16
+DEAL::Diff restrict add l3: 9.93014e-16
+DEAL::Diff restrict     l4: 4.00297e-16
+DEAL::Diff restrict add l4: 4.44089e-16
+DEAL::Diff restrict     l5: 1.13764e-15
+DEAL::Diff restrict add l5: 1.08779e-15
+DEAL::Diff restrict     l6: 1.11576e-15
+DEAL::Diff restrict add l6: 1.60119e-15
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 2.22045e-16
+DEAL::Diff prolongate   l3: 1.92296e-16
+DEAL::Diff prolongate   l4: 4.00297e-16
+DEAL::Diff prolongate   l5: 3.26349e-16
+DEAL::Diff restrict     l1: 4.96507e-16
+DEAL::Diff restrict add l1: 8.88178e-16
+DEAL::Diff restrict     l2: 8.88178e-16
+DEAL::Diff restrict add l2: 9.93014e-16
+DEAL::Diff restrict     l3: 9.28879e-16
+DEAL::Diff restrict add l3: 1.08779e-15
+DEAL::Diff restrict     l4: 1.58960e-15
+DEAL::Diff restrict add l4: 1.73422e-15
+DEAL::Diff restrict     l5: 2.10942e-15
+DEAL::Diff restrict add l5: 2.53170e-15
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 3.87150e-16
+DEAL::Diff prolongate   l2: 8.39463e-16
+DEAL::Diff prolongate   l3: 1.04489e-15
+DEAL::Diff prolongate   l4: 6.84528e-16
+DEAL::Diff restrict     l1: 6.28037e-16
+DEAL::Diff restrict add l1: 8.88178e-16
+DEAL::Diff restrict     l2: 2.67435e-15
+DEAL::Diff restrict add l2: 2.87803e-15
+DEAL::Diff restrict     l3: 3.27845e-15
+DEAL::Diff restrict add l3: 4.18364e-15
+DEAL::Diff restrict     l4: 1.71928e-15
+DEAL::Diff restrict add l4: 1.91010e-15
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 2.36534e-16
+DEAL::Diff prolongate   l2: 8.41983e-16
+DEAL::Diff prolongate   l3: 1.26888e-15
+DEAL::Diff prolongate   l4: 1.72555e-15
+DEAL::Diff prolongate   l5: 1.18848e-15
+DEAL::Diff restrict     l1: 1.25607e-15
+DEAL::Diff restrict add l1: 1.25607e-15
+DEAL::Diff restrict     l2: 2.58708e-15
+DEAL::Diff restrict add l2: 2.68298e-15
+DEAL::Diff restrict     l3: 3.75399e-15
+DEAL::Diff restrict add l3: 4.21300e-15
+DEAL::Diff restrict     l4: 4.85334e-15
+DEAL::Diff restrict add l4: 5.51100e-15
+DEAL::Diff restrict     l5: 3.22837e-15
+DEAL::Diff restrict add l5: 3.83951e-15
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 1.38498e-15
+DEAL::Diff prolongate   l2: 1.34926e-15
+DEAL::Diff prolongate   l3: 1.69608e-15
+DEAL::Diff prolongate   l4: 1.56273e-15
+DEAL::Diff restrict     l1: 3.77517e-15
+DEAL::Diff restrict add l1: 4.00297e-15
+DEAL::Diff restrict     l2: 4.20833e-15
+DEAL::Diff restrict add l2: 4.82404e-15
+DEAL::Diff restrict     l3: 5.06973e-15
+DEAL::Diff restrict add l3: 5.63486e-15
+DEAL::Diff restrict     l4: 5.06820e-15
+DEAL::Diff restrict add l4: 5.54223e-15
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 2.02658e-16
+DEAL::Diff prolongate   l4: 5.37540e-16
+DEAL::Diff prolongate   l5: 4.59437e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 8.88178e-16
+DEAL::Diff restrict add l2: 8.88178e-16
+DEAL::Diff restrict     l3: 1.96104e-15
+DEAL::Diff restrict add l3: 2.12978e-15
+DEAL::Diff restrict     l4: 3.17919e-15
+DEAL::Diff restrict add l4: 3.97205e-15
+DEAL::Diff restrict     l5: 3.37661e-15
+DEAL::Diff restrict add l5: 3.97826e-15
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 2.29404e-16
+DEAL::Diff prolongate   l2: 3.60822e-16
+DEAL::Diff prolongate   l3: 7.51197e-16
+DEAL::Diff prolongate   l4: 1.02364e-15
+DEAL::Diff restrict     l1: 1.25607e-15
+DEAL::Diff restrict add l1: 1.83103e-15
+DEAL::Diff restrict     l2: 2.95411e-15
+DEAL::Diff restrict add l2: 3.14018e-15
+DEAL::Diff restrict     l3: 5.89569e-15
+DEAL::Diff restrict add l3: 6.37388e-15
+DEAL::Diff restrict     l4: 6.45936e-15
+DEAL::Diff restrict add l4: 7.08110e-15
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 1.07692e-15
+DEAL::Diff prolongate   l2: 1.20589e-15
+DEAL::Diff restrict     l1: 5.02430e-15
+DEAL::Diff restrict add l1: 4.61511e-15
+DEAL::Diff restrict     l2: 6.91131e-15
+DEAL::Diff restrict add l2: 6.76052e-15
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 3.78442e-15
+DEAL::Diff prolongate   l2: 5.40000e-15
+DEAL::Diff prolongate   l3: 3.66590e-15
+DEAL::Diff restrict     l1: 2.62434e-14
+DEAL::Diff restrict add l1: 2.64653e-14
+DEAL::Diff restrict     l2: 3.55385e-14
+DEAL::Diff restrict add l2: 3.60157e-14
+DEAL::Diff restrict     l3: 2.16938e-14
+DEAL::Diff restrict add l3: 2.19353e-14
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.82947e-07
+DEAL::Diff prolongate   l3: 2.73352e-07
+DEAL::Diff prolongate   l4: 2.90000e-07
+DEAL::Diff prolongate   l5: 2.38384e-07
+DEAL::Diff restrict     l1: 1.25729e-07
+DEAL::Diff restrict add l1: 1.25729e-07
+DEAL::Diff restrict     l2: 4.51923e-07
+DEAL::Diff restrict add l2: 4.64551e-07
+DEAL::Diff restrict     l3: 5.80701e-07
+DEAL::Diff restrict add l3: 7.99297e-07
+DEAL::Diff restrict     l4: 6.55915e-07
+DEAL::Diff restrict add l4: 9.76871e-07
+DEAL::Diff restrict     l5: 4.91499e-07
+DEAL::Diff restrict add l5: 6.27939e-07
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 3.00343e-08
+DEAL::Diff prolongate   l2: 1.06605e-07
+DEAL::Diff prolongate   l3: 3.42290e-07
+DEAL::Diff prolongate   l4: 3.27767e-07
+DEAL::Diff prolongate   l5: 4.72479e-07
+DEAL::Diff prolongate   l6: 4.70342e-07
+DEAL::Diff restrict     l1: 1.13621e-07
+DEAL::Diff restrict add l1: 1.13621e-07
+DEAL::Diff restrict     l2: 3.72885e-07
+DEAL::Diff restrict add l2: 3.82058e-07
+DEAL::Diff restrict     l3: 6.77499e-07
+DEAL::Diff restrict add l3: 8.80222e-07
+DEAL::Diff restrict     l4: 7.41751e-07
+DEAL::Diff restrict add l4: 1.01957e-06
+DEAL::Diff restrict     l5: 8.74257e-07
+DEAL::Diff restrict add l5: 1.11659e-06
+DEAL::Diff restrict     l6: 9.89949e-07
+DEAL::Diff restrict add l6: 1.16693e-06
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 2.03307e-07
+DEAL::Diff prolongate   l2: 4.70858e-07
+DEAL::Diff prolongate   l3: 4.27724e-07
+DEAL::Diff prolongate   l4: 5.97569e-07
+DEAL::Diff prolongate   l5: 6.83253e-07
+DEAL::Diff restrict     l1: 4.87117e-07
+DEAL::Diff restrict add l1: 7.26694e-07
+DEAL::Diff restrict     l2: 1.09591e-06
+DEAL::Diff restrict add l2: 1.38195e-06
+DEAL::Diff restrict     l3: 9.63365e-07
+DEAL::Diff restrict add l3: 1.11536e-06
+DEAL::Diff restrict     l4: 1.13478e-06
+DEAL::Diff restrict add l4: 1.32608e-06
+DEAL::Diff restrict     l5: 1.39715e-06
+DEAL::Diff restrict add l5: 1.70729e-06
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 3.02644e-08
+DEAL::Diff prolongate   l2: 5.10510e-08
+DEAL::Diff restrict     l1: 3.77651e-07
+DEAL::Diff restrict add l1: 3.77651e-07
+DEAL::Diff restrict     l2: 4.99556e-07
+DEAL::Diff restrict add l2: 4.99556e-07
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 6.05288e-08
+DEAL::Diff prolongate   l2: 2.69857e-07
+DEAL::Diff prolongate   l3: 8.37737e-07
+DEAL::Diff prolongate   l4: 1.27552e-06
+DEAL::Diff prolongate   l5: 1.40443e-06
+DEAL::Diff restrict     l1: 6.15662e-07
+DEAL::Diff restrict add l1: 6.15662e-07
+DEAL::Diff restrict     l2: 1.21900e-06
+DEAL::Diff restrict add l2: 1.34318e-06
+DEAL::Diff restrict     l3: 2.64206e-06
+DEAL::Diff restrict add l3: 2.85523e-06
+DEAL::Diff restrict     l4: 3.79070e-06
+DEAL::Diff restrict add l4: 4.12862e-06
+DEAL::Diff restrict     l5: 3.57424e-06
+DEAL::Diff restrict add l5: 3.89088e-06
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 8.63082e-07
+DEAL::Diff prolongate   l2: 1.02885e-06
+DEAL::Diff prolongate   l3: 1.86363e-06
+DEAL::Diff prolongate   l4: 2.64187e-06
+DEAL::Diff restrict     l1: 2.70130e-06
+DEAL::Diff restrict add l1: 2.81647e-06
+DEAL::Diff restrict     l2: 3.09755e-06
+DEAL::Diff restrict add l2: 3.25362e-06
+DEAL::Diff restrict     l3: 4.73380e-06
+DEAL::Diff restrict add l3: 5.08899e-06
+DEAL::Diff restrict     l4: 6.73984e-06
+DEAL::Diff restrict add l4: 7.45000e-06
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_02.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..98d496e
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.11022e-16
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 5.55112e-17
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 4.44089e-16
+DEAL::Diff restrict add l3: 4.44089e-16
+DEAL::Diff restrict     l4: 6.75322e-16
+DEAL::Diff restrict add l4: 6.66134e-16
+DEAL::Diff restrict     l5: 4.00297e-16
+DEAL::Diff restrict add l5: 4.44089e-16
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 5.55112e-17
+DEAL::Diff prolongate   l4: 9.61481e-17
+DEAL::Diff prolongate   l5: 1.92296e-16
+DEAL::Diff prolongate   l6: 2.09665e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 5.87475e-16
+DEAL::Diff restrict add l3: 6.28037e-16
+DEAL::Diff restrict     l4: 3.33067e-16
+DEAL::Diff restrict add l4: 4.96507e-16
+DEAL::Diff restrict     l5: 8.75951e-16
+DEAL::Diff restrict add l5: 1.13221e-15
+DEAL::Diff restrict     l6: 1.49365e-15
+DEAL::Diff restrict add l6: 1.53837e-15
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.92296e-16
+DEAL::Diff prolongate   l3: 2.09550e-16
+DEAL::Diff prolongate   l4: 3.18887e-16
+DEAL::Diff prolongate   l5: 3.14325e-16
+DEAL::Diff restrict     l1: 4.96507e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 1.17495e-15
+DEAL::Diff restrict add l2: 1.17495e-15
+DEAL::Diff restrict     l3: 1.15911e-15
+DEAL::Diff restrict add l3: 1.35064e-15
+DEAL::Diff restrict     l4: 1.20089e-15
+DEAL::Diff restrict add l4: 1.61651e-15
+DEAL::Diff restrict     l5: 1.72353e-15
+DEAL::Diff restrict add l5: 1.94843e-15
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 2.93415e-16
+DEAL::Diff prolongate   l2: 1.12179e-15
+DEAL::Diff prolongate   l3: 8.90270e-16
+DEAL::Diff prolongate   l4: 9.68765e-16
+DEAL::Diff restrict     l1: 7.69185e-16
+DEAL::Diff restrict add l1: 8.88178e-16
+DEAL::Diff restrict     l2: 2.12398e-15
+DEAL::Diff restrict add l2: 1.67640e-15
+DEAL::Diff restrict     l3: 1.93335e-15
+DEAL::Diff restrict add l3: 1.99840e-15
+DEAL::Diff restrict     l4: 1.65070e-15
+DEAL::Diff restrict add l4: 1.79018e-15
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 4.19100e-16
+DEAL::Diff prolongate   l2: 7.23163e-16
+DEAL::Diff prolongate   l3: 1.49879e-15
+DEAL::Diff prolongate   l4: 1.67926e-15
+DEAL::Diff prolongate   l5: 1.34221e-15
+DEAL::Diff restrict     l1: 3.84593e-16
+DEAL::Diff restrict add l1: 6.28037e-16
+DEAL::Diff restrict     l2: 1.88738e-15
+DEAL::Diff restrict add l2: 1.99840e-15
+DEAL::Diff restrict     l3: 3.40071e-15
+DEAL::Diff restrict add l3: 3.43990e-15
+DEAL::Diff restrict     l4: 3.82627e-15
+DEAL::Diff restrict add l4: 3.64180e-15
+DEAL::Diff restrict     l5: 3.84392e-15
+DEAL::Diff restrict add l5: 4.40746e-15
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 1.54021e-15
+DEAL::Diff prolongate   l2: 1.55808e-15
+DEAL::Diff prolongate   l3: 2.01813e-15
+DEAL::Diff prolongate   l4: 1.80659e-15
+DEAL::Diff restrict     l1: 3.42779e-15
+DEAL::Diff restrict add l1: 3.95962e-15
+DEAL::Diff restrict     l2: 3.98735e-15
+DEAL::Diff restrict add l2: 4.56138e-15
+DEAL::Diff restrict     l3: 4.36875e-15
+DEAL::Diff restrict add l3: 5.08283e-15
+DEAL::Diff restrict     l4: 4.48817e-15
+DEAL::Diff restrict add l4: 5.31053e-15
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 2.18548e-16
+DEAL::Diff prolongate   l4: 4.49062e-16
+DEAL::Diff prolongate   l5: 5.55805e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 2.03507e-15
+DEAL::Diff restrict add l3: 2.03507e-15
+DEAL::Diff restrict     l4: 3.29345e-15
+DEAL::Diff restrict add l4: 3.46845e-15
+DEAL::Diff restrict     l5: 2.99760e-15
+DEAL::Diff restrict add l5: 3.68888e-15
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 2.60370e-16
+DEAL::Diff prolongate   l2: 4.20018e-16
+DEAL::Diff prolongate   l3: 6.98592e-16
+DEAL::Diff prolongate   l4: 1.25803e-15
+DEAL::Diff restrict     l1: 1.25607e-15
+DEAL::Diff restrict add l1: 9.93014e-16
+DEAL::Diff restrict     l2: 2.22045e-15
+DEAL::Diff restrict add l2: 2.39149e-15
+DEAL::Diff restrict     l3: 3.57347e-15
+DEAL::Diff restrict add l3: 3.60780e-15
+DEAL::Diff restrict     l4: 5.93424e-15
+DEAL::Diff restrict add l4: 7.19164e-15
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 6.25665e-16
+DEAL::Diff prolongate   l2: 1.12982e-15
+DEAL::Diff restrict     l1: 3.07674e-15
+DEAL::Diff restrict add l1: 2.80867e-15
+DEAL::Diff restrict     l2: 7.89196e-15
+DEAL::Diff restrict add l2: 8.16448e-15
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 4.47538e-15
+DEAL::Diff prolongate   l2: 6.65118e-15
+DEAL::Diff prolongate   l3: 4.28755e-15
+DEAL::Diff restrict     l1: 2.07451e-14
+DEAL::Diff restrict add l1: 2.17150e-14
+DEAL::Diff restrict     l2: 2.76721e-14
+DEAL::Diff restrict add l2: 2.85472e-14
+DEAL::Diff restrict     l3: 2.07301e-14
+DEAL::Diff restrict add l3: 2.14859e-14
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 1.53598e-08
+DEAL::Diff prolongate   l2: 1.32451e-07
+DEAL::Diff prolongate   l3: 2.77478e-07
+DEAL::Diff prolongate   l4: 2.43327e-07
+DEAL::Diff prolongate   l5: 1.99307e-07
+DEAL::Diff restrict     l1: 1.55531e-07
+DEAL::Diff restrict add l1: 1.55531e-07
+DEAL::Diff restrict     l2: 1.80699e-07
+DEAL::Diff restrict add l2: 2.68656e-07
+DEAL::Diff restrict     l3: 5.31998e-07
+DEAL::Diff restrict add l3: 6.10878e-07
+DEAL::Diff restrict     l4: 6.72091e-07
+DEAL::Diff restrict add l4: 7.96976e-07
+DEAL::Diff restrict     l5: 4.78152e-07
+DEAL::Diff restrict add l5: 6.10737e-07
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 9.31323e-09
+DEAL::Diff prolongate   l2: 1.14023e-07
+DEAL::Diff prolongate   l3: 3.02950e-07
+DEAL::Diff prolongate   l4: 3.31972e-07
+DEAL::Diff prolongate   l5: 4.83178e-07
+DEAL::Diff prolongate   l6: 4.49200e-07
+DEAL::Diff restrict     l1: 1.00117e-08
+DEAL::Diff restrict add l1: 1.00117e-08
+DEAL::Diff restrict     l2: 3.03629e-07
+DEAL::Diff restrict add l2: 3.35049e-07
+DEAL::Diff restrict     l3: 6.96781e-07
+DEAL::Diff restrict add l3: 9.83613e-07
+DEAL::Diff restrict     l4: 6.53890e-07
+DEAL::Diff restrict add l4: 7.96383e-07
+DEAL::Diff restrict     l5: 1.05105e-06
+DEAL::Diff restrict add l5: 1.35094e-06
+DEAL::Diff restrict     l6: 9.63780e-07
+DEAL::Diff restrict add l6: 1.22002e-06
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 1.96297e-07
+DEAL::Diff prolongate   l2: 4.29379e-07
+DEAL::Diff prolongate   l3: 3.78592e-07
+DEAL::Diff prolongate   l4: 5.48624e-07
+DEAL::Diff prolongate   l5: 7.03000e-07
+DEAL::Diff restrict     l1: 3.35044e-07
+DEAL::Diff restrict add l1: 3.89982e-07
+DEAL::Diff restrict     l2: 1.15122e-06
+DEAL::Diff restrict add l2: 1.32525e-06
+DEAL::Diff restrict     l3: 1.00435e-06
+DEAL::Diff restrict add l3: 1.22192e-06
+DEAL::Diff restrict     l4: 1.23935e-06
+DEAL::Diff restrict add l4: 1.47309e-06
+DEAL::Diff restrict     l5: 1.32602e-06
+DEAL::Diff restrict add l5: 1.91723e-06
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 1.05367e-08
+DEAL::Diff prolongate   l2: 1.17397e-07
+DEAL::Diff restrict     l1: 2.84635e-07
+DEAL::Diff restrict add l1: 2.84635e-07
+DEAL::Diff restrict     l2: 5.41568e-07
+DEAL::Diff restrict add l2: 8.78831e-07
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 1.39089e-07
+DEAL::Diff prolongate   l2: 3.79811e-07
+DEAL::Diff prolongate   l3: 1.01625e-06
+DEAL::Diff prolongate   l4: 1.27553e-06
+DEAL::Diff prolongate   l5: 1.29250e-06
+DEAL::Diff restrict     l1: 1.37952e-07
+DEAL::Diff restrict add l1: 1.37952e-07
+DEAL::Diff restrict     l2: 1.18038e-06
+DEAL::Diff restrict add l2: 1.25114e-06
+DEAL::Diff restrict     l3: 2.41311e-06
+DEAL::Diff restrict add l3: 2.66759e-06
+DEAL::Diff restrict     l4: 3.55824e-06
+DEAL::Diff restrict add l4: 3.81845e-06
+DEAL::Diff restrict     l5: 3.73363e-06
+DEAL::Diff restrict add l5: 4.00464e-06
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 9.71673e-07
+DEAL::Diff prolongate   l2: 1.00927e-06
+DEAL::Diff prolongate   l3: 1.78966e-06
+DEAL::Diff prolongate   l4: 2.55606e-06
+DEAL::Diff restrict     l1: 2.80919e-06
+DEAL::Diff restrict add l1: 2.85094e-06
+DEAL::Diff restrict     l2: 2.81573e-06
+DEAL::Diff restrict add l2: 3.01700e-06
+DEAL::Diff restrict     l3: 4.79409e-06
+DEAL::Diff restrict add l3: 5.48025e-06
+DEAL::Diff restrict     l4: 6.45920e-06
+DEAL::Diff restrict add l4: 7.19753e-06
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02_block.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_02_block.cc
new file mode 100644 (file)
index 0000000..2d158b7
--- /dev/null
@@ -0,0 +1,200 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferBlockMatrixFree by comparison with MGTransferMatrixFree on a
+// series of adaptive meshes for FE_Q. This is, essentially, a
+// copy-paste of transfer_matrix_free_02.cc
+
+#include <deal.II/base/logstream.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_block_vector.h>
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference
+      MGTransferMF<dim, Number> transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferBlockMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      const unsigned int nb = 3;
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::BlockVector<Number> v1(nb), v2(nb),
+            v3(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            {
+              v1.block(b).reinit(mgdof.locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+              v2.block(b).reinit(mgdof.locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+              v3.block(b).reinit(mgdof.locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+
+              for (unsigned int i = 0; i < v1.block(b).locally_owned_size();
+                   ++i)
+                v1.block(b).local_element(i) = random_value<double>();
+
+              transfer_ref.prolongate(level, v2.block(b), v1.block(b));
+            }
+
+          transfer.prolongate(level, v3, v1);
+          v3 -= v2;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::BlockVector<Number> v1(nb), v2(nb),
+            v3(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            {
+              v1.block(b).reinit(mgdof.locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+              v2.block(b).reinit(mgdof.locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+              v3.block(b).reinit(mgdof.locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+
+              for (unsigned int i = 0; i < v1.block(b).locally_owned_size();
+                   ++i)
+                v1.block(b).local_element(i) = random_value<double>();
+
+              transfer_ref.restrict_and_add(level, v2.block(b), v1.block(b));
+            }
+
+          transfer.restrict_and_add(level, v3, v1);
+          v3 -= v2;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          for (unsigned int b = 0; b < nb; ++b)
+            transfer_ref.restrict_and_add(level, v3.block(b), v1.block(b));
+          v3 -= v2;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02_block.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_02_block.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..40a8160
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff prolongate   l6: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::Diff restrict     l6: 0
+DEAL::Diff restrict add l6: 0
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff prolongate   l6: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::Diff restrict     l6: 0
+DEAL::Diff restrict add l6: 0
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff prolongate   l5: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::Diff restrict     l5: 0
+DEAL::Diff restrict add l5: 0
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff prolongate   l3: 0
+DEAL::Diff prolongate   l4: 0
+DEAL::Diff restrict     l1: 0
+DEAL::Diff restrict add l1: 0
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::Diff restrict     l3: 0
+DEAL::Diff restrict add l3: 0
+DEAL::Diff restrict     l4: 0
+DEAL::Diff restrict add l4: 0
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.cc
new file mode 100644 (file)
index 0000000..7ede5f7
--- /dev/null
@@ -0,0 +1,218 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferBlockMatrixFree by comparison with MGTransferMatrixFree on a
+// series of adaptive meshes for FE_Q. This is similar to
+// transfer_matrix_free_02.cc but using separate DoFHandlers for each block.
+
+#include <deal.II/base/logstream.h>
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_block_vector.h>
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  const unsigned int nb = 2;
+
+  FE_Q<dim> fe_1(fe_degree + 1);
+  FE_Q<dim> fe_2(fe_degree);
+
+  deallog << "FE: " << fe_1.get_name() << std::endl;
+  deallog << "FE: " << fe_2.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof_1(tr);
+      mgdof_1.distribute_dofs(fe_1);
+      mgdof_1.distribute_mg_dofs();
+
+      DoFHandler<dim> mgdof_2(tr);
+      mgdof_2.distribute_dofs(fe_2);
+      mgdof_2.distribute_mg_dofs();
+
+      const std::vector<const DoFHandler<dim> *> mgdof_ptr{&mgdof_1, &mgdof_2};
+
+      std::vector<MGConstrainedDoFs> mg_constrained_dofs_vector(2);
+      for (unsigned int i = 0; i < mgdof_ptr.size(); ++i)
+        {
+          mg_constrained_dofs_vector[i].initialize(*mgdof_ptr[i]);
+          mg_constrained_dofs_vector[i].make_zero_boundary_constraints(
+            *mgdof_ptr[i], {0});
+        }
+
+      // build reference
+      std::vector<MGTransferMF<dim, Number>> transfer_ref;
+      for (unsigned int b = 0; b < nb; ++b)
+        {
+          transfer_ref.emplace_back(mg_constrained_dofs_vector[b]);
+          transfer_ref[b].build(*mgdof_ptr[b]);
+        }
+
+      // build matrix-free transfer
+      MGTransferBlockMF<dim, Number> transfer(mg_constrained_dofs_vector);
+      transfer.build(mgdof_ptr);
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof_ptr[0]->get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::BlockVector<Number> v1(nb), v2(nb),
+            v3(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            {
+              v1.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+              v2.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+              v3.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+
+              for (unsigned int i = 0; i < v1.block(b).locally_owned_size();
+                   ++i)
+                v1.block(b).local_element(i) = random_value<double>();
+
+              transfer_ref[b].prolongate(level, v2.block(b), v1.block(b));
+            }
+
+          transfer.prolongate(level, v3, v1);
+          v3 -= v2;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof_ptr[0]->get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::BlockVector<Number> v1(nb), v2(nb),
+            v3(nb);
+          for (unsigned int b = 0; b < nb; ++b)
+            {
+              v1.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level),
+                                 MPI_COMM_WORLD);
+              v2.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+              v3.block(b).reinit(mgdof_ptr[b]->locally_owned_mg_dofs(level - 1),
+                                 MPI_COMM_WORLD);
+
+              for (unsigned int i = 0; i < v1.block(b).locally_owned_size();
+                   ++i)
+                v1.block(b).local_element(i) = random_value<double>();
+
+              transfer_ref[b].restrict_and_add(level, v2.block(b), v1.block(b));
+            }
+
+          transfer.restrict_and_add(level, v3, v1);
+          v3 -= v2;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          for (unsigned int b = 0; b < nb; ++b)
+            transfer_ref[b].restrict_and_add(level, v3.block(b), v1.block(b));
+          v3 -= v2;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_02_block_02.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..62ed8e7
--- /dev/null
@@ -0,0 +1,265 @@
+
+DEAL::FE: FE_Q<2>(2)
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(4)
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(4)
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_03.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_03.cc
new file mode 100644 (file)
index 0000000..0a5d1b2
--- /dev/null
@@ -0,0 +1,154 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with adaptive meshes for FE_Q (similar to
+// transfer_matrix_free_02 but on a different mesh refining into a corner)
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  parallel::distributed::Triangulation<dim> tr(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::subdivided_hyper_cube(tr, 3);
+  for (unsigned int cycle = 0; cycle < (dim == 2 ? 10 : 7); ++cycle)
+    {
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->vertex(0).norm() < 1e-10)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << " on "
+              << tr.n_global_levels() << " levels" << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      const Number tolerance = 1000. * std::numeric_limits<Number>::epsilon();
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_03.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_03.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..7034cc0
--- /dev/null
@@ -0,0 +1,856 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 12 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 15 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 18 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 21 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 24 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 27 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 30 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
+DEAL::no. cells: 33 on 9 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::
+DEAL::no. cells: 36 on 10 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::
+DEAL::no. cells: 39 on 11 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff prolongate   l10: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::Diff restrict     l10: 0.00000
+DEAL::Diff restrict add l10: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(3)
+DEAL::no. cells: 12 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 15 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 18 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 21 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 24 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 27 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 30 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
+DEAL::no. cells: 33 on 9 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::
+DEAL::no. cells: 36 on 10 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::
+DEAL::no. cells: 39 on 11 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff prolongate   l10: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::Diff restrict     l10: 0.00000
+DEAL::Diff restrict add l10: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 34 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 41 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 48 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 55 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 62 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 69 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 76 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(3)
+DEAL::no. cells: 34 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 41 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 48 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 55 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 62 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 69 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 76 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 12 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 15 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 18 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 21 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 24 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 27 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 30 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
+DEAL::no. cells: 33 on 9 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::
+DEAL::no. cells: 36 on 10 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::
+DEAL::no. cells: 39 on 11 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff prolongate   l8: 0.00000
+DEAL::Diff prolongate   l9: 0.00000
+DEAL::Diff prolongate   l10: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::Diff restrict     l8: 0.00000
+DEAL::Diff restrict add l8: 0.00000
+DEAL::Diff restrict     l9: 0.00000
+DEAL::Diff restrict add l9: 0.00000
+DEAL::Diff restrict     l10: 0.00000
+DEAL::Diff restrict add l10: 0.00000
+DEAL::
+DEAL::FE: FE_Q<3>(2)
+DEAL::no. cells: 34 on 2 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 41 on 3 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 48 on 4 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 55 on 5 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 62 on 6 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 69 on 7 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 76 on 8 levels
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff prolongate   l7: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::Diff restrict     l7: 0.00000
+DEAL::Diff restrict add l7: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_04.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_04.cc
new file mode 100644 (file)
index 0000000..e5adc27
--- /dev/null
@@ -0,0 +1,161 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with uniform meshes for FE_DGQ (except for the different
+// element and no constraints the same test as transfer_matrix_free_01)
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_dgq.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_DGQ<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3, 4, 5, 6, 8};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref;
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer;
+      transfer.build(mgdof);
+
+      const Number tolerance = 1000. * std::numeric_limits<Number>::epsilon();
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          IndexSet relevant_set;
+          DoFTools::extract_locally_relevant_level_dofs(mgdof,
+                                                        level,
+                                                        relevant_set);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level),
+                    relevant_set,
+                    MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+          deallog << "Vectors have ghosts: " << v2.has_ghost_elements() << ' '
+                  << v3.has_ghost_elements() << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=1.output b/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..c126ad7
--- /dev/null
@@ -0,0 +1,455 @@
+
+DEAL::FE: FE_DGQ<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 3.02285e-13
+DEAL::Diff restrict add l3: 3.02551e-13
+DEAL::
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=4.output b/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..c126ad7
--- /dev/null
@@ -0,0 +1,455 @@
+
+DEAL::FE: FE_DGQ<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 3.02285e-13
+DEAL::Diff restrict add l3: 3.02551e-13
+DEAL::
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=7.output b/tests/multigrid-global-coarsening/transfer_matrix_free_04.with_p4est=true.with_trilinos=true.mpirun=7.output
new file mode 100644 (file)
index 0000000..c126ad7
--- /dev/null
@@ -0,0 +1,455 @@
+
+DEAL::FE: FE_DGQ<2>(1)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 4
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 36
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 100
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(1)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 27
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 125
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 3.02285e-13
+DEAL::Diff restrict add l3: 3.02551e-13
+DEAL::
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 16
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 144
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 256
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 400
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 576
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1024
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(2)
+DEAL::no. cells: 8
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 64
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 216
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 512
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::no. cells: 1000
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::
+DEAL::no. cells: 1728
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 4096
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Vectors have ghosts: 0 0
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_05.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_05.cc
new file mode 100644 (file)
index 0000000..8aef5d8
--- /dev/null
@@ -0,0 +1,180 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with adaptive meshes for FE_DGQ (except for the different
+// element and no constraints the same test as transfer_matrix_free_01)
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_dgq.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_DGQ<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref;
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer;
+      transfer.build(mgdof);
+
+      const Number tolerance = 1000. * std::numeric_limits<Number>::epsilon();
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": "
+                  << filter_out_small_numbers(v3.l2_norm(), tolerance)
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=1.output b/tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..5777a0a
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_DGQ<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_05.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..5777a0a
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_DGQ<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff prolongate   l6: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::Diff restrict     l6: 0.00000
+DEAL::Diff restrict add l6: 0.00000
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::FE: FE_DGQ<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff prolongate   l5: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::Diff restrict     l5: 0.00000
+DEAL::Diff restrict add l5: 0.00000
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 0.00000
+DEAL::Diff prolongate   l4: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 0.00000
+DEAL::Diff restrict add l3: 0.00000
+DEAL::Diff restrict     l4: 0.00000
+DEAL::Diff restrict add l4: 0.00000
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_06.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_06.cc
new file mode 100644 (file)
index 0000000..932fb3b
--- /dev/null
@@ -0,0 +1,182 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with adaptive meshes for FESystem(FE_Q,2). Same as
+// transfer_matrix_free_02 but using two components (and fewer meshes).
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FESystem<dim> fe(FE_Q<dim>(fe_degree), 2);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 6 - 2 * dim;
+      if (fe_degree == 1)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+      transfer.build(mgdof);
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=10.output b/tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=10.output
new file mode 100644 (file)
index 0000000..2f9f6a1
--- /dev/null
@@ -0,0 +1,169 @@
+
+DEAL::FE: FESystem<2>[FE_Q<2>(1)^2]
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.92296e-16
+DEAL::Diff prolongate   l4: 1.57009e-16
+DEAL::Diff prolongate   l5: 4.04127e-16
+DEAL::Diff prolongate   l6: 3.12789e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 1.08779e-15
+DEAL::Diff restrict add l3: 1.17495e-15
+DEAL::Diff restrict     l4: 1.23629e-15
+DEAL::Diff restrict add l4: 1.25607e-15
+DEAL::Diff restrict     l5: 1.52226e-15
+DEAL::Diff restrict add l5: 1.77636e-15
+DEAL::Diff restrict     l6: 1.80390e-15
+DEAL::Diff restrict add l6: 2.28609e-15
+DEAL::
+DEAL::no. cells: 868
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 5.55112e-17
+DEAL::Diff prolongate   l4: 3.68219e-16
+DEAL::Diff prolongate   l5: 4.02217e-16
+DEAL::Diff prolongate   l6: 5.88130e-16
+DEAL::Diff prolongate   l7: 6.83331e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 0.00000
+DEAL::Diff restrict add l2: 0.00000
+DEAL::Diff restrict     l3: 9.67870e-16
+DEAL::Diff restrict add l3: 9.93014e-16
+DEAL::Diff restrict     l4: 2.38116e-15
+DEAL::Diff restrict add l4: 2.48253e-15
+DEAL::Diff restrict     l5: 2.18970e-15
+DEAL::Diff restrict add l5: 2.55110e-15
+DEAL::Diff restrict     l6: 2.51705e-15
+DEAL::Diff restrict add l6: 3.00376e-15
+DEAL::Diff restrict     l7: 3.57390e-15
+DEAL::Diff restrict add l7: 3.91580e-15
+DEAL::
+DEAL::FE: FESystem<2>[FE_Q<2>(3)^2]
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 1.19375e-15
+DEAL::Diff prolongate   l2: 2.65120e-15
+DEAL::Diff prolongate   l3: 4.51475e-15
+DEAL::Diff prolongate   l4: 5.36184e-15
+DEAL::Diff prolongate   l5: 4.26321e-15
+DEAL::Diff restrict     l1: 1.93574e-15
+DEAL::Diff restrict add l1: 2.03507e-15
+DEAL::Diff restrict     l2: 5.61733e-15
+DEAL::Diff restrict add l2: 6.25283e-15
+DEAL::Diff restrict     l3: 8.89530e-15
+DEAL::Diff restrict add l3: 9.36017e-15
+DEAL::Diff restrict     l4: 1.09472e-14
+DEAL::Diff restrict add l4: 1.09665e-14
+DEAL::Diff restrict     l5: 8.06786e-15
+DEAL::Diff restrict add l5: 8.16750e-15
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 1.04513e-15
+DEAL::Diff prolongate   l2: 2.59807e-15
+DEAL::Diff prolongate   l3: 5.95414e-15
+DEAL::Diff prolongate   l4: 6.00254e-15
+DEAL::Diff prolongate   l5: 8.39305e-15
+DEAL::Diff prolongate   l6: 8.37666e-15
+DEAL::Diff restrict     l1: 2.51215e-15
+DEAL::Diff restrict add l1: 3.20237e-15
+DEAL::Diff restrict     l2: 6.21923e-15
+DEAL::Diff restrict add l2: 6.46985e-15
+DEAL::Diff restrict     l3: 1.30151e-14
+DEAL::Diff restrict add l3: 1.42247e-14
+DEAL::Diff restrict     l4: 1.26215e-14
+DEAL::Diff restrict add l4: 1.28133e-14
+DEAL::Diff restrict     l5: 1.56220e-14
+DEAL::Diff restrict add l5: 1.64807e-14
+DEAL::Diff restrict     l6: 1.56927e-14
+DEAL::Diff restrict add l6: 1.66947e-14
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(1)^2]
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 3.14018e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 5.55112e-17
+DEAL::Diff prolongate   l3: 4.45173e-16
+DEAL::Diff prolongate   l4: 5.76095e-16
+DEAL::Diff prolongate   l5: 8.29336e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 8.88178e-16
+DEAL::Diff restrict add l2: 8.88178e-16
+DEAL::Diff restrict     l3: 2.02292e-15
+DEAL::Diff restrict add l3: 2.22045e-15
+DEAL::Diff restrict     l4: 3.95027e-15
+DEAL::Diff restrict add l4: 4.19541e-15
+DEAL::Diff restrict     l5: 4.67350e-15
+DEAL::Diff restrict add l5: 5.25453e-15
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(3)^2]
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 7.45167e-15
+DEAL::Diff prolongate   l2: 8.99804e-15
+DEAL::Diff restrict     l1: 2.31609e-14
+DEAL::Diff restrict add l1: 2.25394e-14
+DEAL::Diff restrict     l2: 3.06553e-14
+DEAL::Diff restrict add l2: 3.12389e-14
+DEAL::
+DEAL::FE: FESystem<2>[FE_Q<2>(2)^2]
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 6.86910e-08
+DEAL::Diff prolongate   l2: 1.77133e-07
+DEAL::Diff prolongate   l3: 3.21812e-07
+DEAL::Diff prolongate   l4: 4.07741e-07
+DEAL::Diff prolongate   l5: 3.15483e-07
+DEAL::Diff restrict     l1: 8.43965e-08
+DEAL::Diff restrict add l1: 3.78172e-07
+DEAL::Diff restrict     l2: 4.04207e-07
+DEAL::Diff restrict add l2: 5.76620e-07
+DEAL::Diff restrict     l3: 7.63684e-07
+DEAL::Diff restrict add l3: 9.19822e-07
+DEAL::Diff restrict     l4: 9.23719e-07
+DEAL::Diff restrict add l4: 1.08789e-06
+DEAL::Diff restrict     l5: 7.03670e-07
+DEAL::Diff restrict add l5: 9.16036e-07
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 7.48774e-08
+DEAL::Diff prolongate   l2: 1.80284e-07
+DEAL::Diff prolongate   l3: 4.12573e-07
+DEAL::Diff prolongate   l4: 4.89806e-07
+DEAL::Diff prolongate   l5: 7.08827e-07
+DEAL::Diff prolongate   l6: 6.86261e-07
+DEAL::Diff restrict     l1: 4.86098e-08
+DEAL::Diff restrict add l1: 4.86098e-08
+DEAL::Diff restrict     l2: 4.41927e-07
+DEAL::Diff restrict add l2: 4.56242e-07
+DEAL::Diff restrict     l3: 8.35079e-07
+DEAL::Diff restrict add l3: 1.19002e-06
+DEAL::Diff restrict     l4: 1.03492e-06
+DEAL::Diff restrict add l4: 1.30417e-06
+DEAL::Diff restrict     l5: 1.26083e-06
+DEAL::Diff restrict add l5: 1.66426e-06
+DEAL::Diff restrict     l6: 1.45183e-06
+DEAL::Diff restrict add l6: 1.82397e-06
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(2)^2]
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 7.18146e-08
+DEAL::Diff prolongate   l2: 2.81848e-07
+DEAL::Diff restrict     l1: 1.78137e-07
+DEAL::Diff restrict add l1: 1.78137e-07
+DEAL::Diff restrict     l2: 5.02891e-07
+DEAL::Diff restrict add l2: 5.02891e-07
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_06.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..4423d36
--- /dev/null
@@ -0,0 +1,169 @@
+
+DEAL::FE: FESystem<2>[FE_Q<2>(1)^2]
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 9.61481e-17
+DEAL::Diff prolongate   l4: 2.54384e-16
+DEAL::Diff prolongate   l5: 2.97645e-16
+DEAL::Diff prolongate   l6: 3.06884e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 1.08779e-15
+DEAL::Diff restrict add l3: 1.08779e-15
+DEAL::Diff restrict     l4: 1.02958e-15
+DEAL::Diff restrict add l4: 9.42055e-16
+DEAL::Diff restrict     l5: 1.62032e-15
+DEAL::Diff restrict add l5: 1.89715e-15
+DEAL::Diff restrict     l6: 1.36877e-15
+DEAL::Diff restrict add l6: 1.58572e-15
+DEAL::
+DEAL::no. cells: 868
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff prolongate   l3: 1.24127e-16
+DEAL::Diff prolongate   l4: 2.93737e-16
+DEAL::Diff prolongate   l5: 3.78536e-16
+DEAL::Diff prolongate   l6: 4.20991e-16
+DEAL::Diff prolongate   l7: 7.17496e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 4.44089e-16
+DEAL::Diff restrict     l3: 1.29948e-15
+DEAL::Diff restrict add l3: 1.53837e-15
+DEAL::Diff restrict     l4: 2.39149e-15
+DEAL::Diff restrict add l4: 2.73755e-15
+DEAL::Diff restrict     l5: 2.31289e-15
+DEAL::Diff restrict add l5: 2.52194e-15
+DEAL::Diff restrict     l6: 2.37663e-15
+DEAL::Diff restrict add l6: 2.86084e-15
+DEAL::Diff restrict     l7: 3.38936e-15
+DEAL::Diff restrict add l7: 3.79430e-15
+DEAL::
+DEAL::FE: FESystem<2>[FE_Q<2>(3)^2]
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 1.24251e-15
+DEAL::Diff prolongate   l2: 2.69354e-15
+DEAL::Diff prolongate   l3: 4.71393e-15
+DEAL::Diff prolongate   l4: 5.25000e-15
+DEAL::Diff prolongate   l5: 4.24784e-15
+DEAL::Diff restrict     l1: 3.10862e-15
+DEAL::Diff restrict add l1: 3.29345e-15
+DEAL::Diff restrict     l2: 4.53980e-15
+DEAL::Diff restrict add l2: 5.00955e-15
+DEAL::Diff restrict     l3: 8.75679e-15
+DEAL::Diff restrict add l3: 8.96466e-15
+DEAL::Diff restrict     l4: 9.88904e-15
+DEAL::Diff restrict add l4: 9.94006e-15
+DEAL::Diff restrict     l5: 8.14781e-15
+DEAL::Diff restrict add l5: 8.59115e-15
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 1.23403e-15
+DEAL::Diff prolongate   l2: 2.59030e-15
+DEAL::Diff prolongate   l3: 6.19756e-15
+DEAL::Diff prolongate   l4: 5.86430e-15
+DEAL::Diff prolongate   l5: 8.02510e-15
+DEAL::Diff prolongate   l6: 7.89235e-15
+DEAL::Diff restrict     l1: 2.04715e-15
+DEAL::Diff restrict add l1: 2.73755e-15
+DEAL::Diff restrict     l2: 6.29801e-15
+DEAL::Diff restrict add l2: 6.23704e-15
+DEAL::Diff restrict     l3: 1.33072e-14
+DEAL::Diff restrict add l3: 1.33171e-14
+DEAL::Diff restrict     l4: 1.26068e-14
+DEAL::Diff restrict add l4: 1.29130e-14
+DEAL::Diff restrict     l5: 1.74281e-14
+DEAL::Diff restrict add l5: 1.78908e-14
+DEAL::Diff restrict     l6: 1.64922e-14
+DEAL::Diff restrict add l6: 1.73113e-14
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(1)^2]
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 3.14018e-16
+DEAL::Diff restrict add l2: 0.00000
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 0.00000
+DEAL::Diff prolongate   l2: 1.14439e-16
+DEAL::Diff prolongate   l3: 4.48405e-16
+DEAL::Diff prolongate   l4: 6.43898e-16
+DEAL::Diff prolongate   l5: 7.94566e-16
+DEAL::Diff restrict     l1: 0.00000
+DEAL::Diff restrict add l1: 0.00000
+DEAL::Diff restrict     l2: 4.44089e-16
+DEAL::Diff restrict add l2: 8.88178e-16
+DEAL::Diff restrict     l3: 2.38116e-15
+DEAL::Diff restrict add l3: 2.73755e-15
+DEAL::Diff restrict     l4: 4.36248e-15
+DEAL::Diff restrict add l4: 4.39626e-15
+DEAL::Diff restrict     l5: 4.33982e-15
+DEAL::Diff restrict add l5: 4.80356e-15
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(3)^2]
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 6.10586e-15
+DEAL::Diff prolongate   l2: 9.12753e-15
+DEAL::Diff restrict     l1: 2.16468e-14
+DEAL::Diff restrict add l1: 2.17558e-14
+DEAL::Diff restrict     l2: 3.10285e-14
+DEAL::Diff restrict add l2: 3.09280e-14
+DEAL::
+DEAL::FE: FESystem<2>[FE_Q<2>(2)^2]
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 3.75428e-08
+DEAL::Diff prolongate   l2: 1.73474e-07
+DEAL::Diff prolongate   l3: 4.06743e-07
+DEAL::Diff prolongate   l4: 4.56267e-07
+DEAL::Diff prolongate   l5: 3.02844e-07
+DEAL::Diff restrict     l1: 7.83696e-08
+DEAL::Diff restrict add l1: 7.83696e-08
+DEAL::Diff restrict     l2: 4.84892e-07
+DEAL::Diff restrict add l2: 4.84892e-07
+DEAL::Diff restrict     l3: 6.33157e-07
+DEAL::Diff restrict add l3: 8.51716e-07
+DEAL::Diff restrict     l4: 7.38227e-07
+DEAL::Diff restrict add l4: 1.08434e-06
+DEAL::Diff restrict     l5: 7.53959e-07
+DEAL::Diff restrict add l5: 9.85545e-07
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 3.80021e-08
+DEAL::Diff prolongate   l2: 2.05445e-07
+DEAL::Diff prolongate   l3: 4.23083e-07
+DEAL::Diff prolongate   l4: 4.60938e-07
+DEAL::Diff prolongate   l5: 6.34151e-07
+DEAL::Diff prolongate   l6: 6.66574e-07
+DEAL::Diff restrict     l1: 1.51135e-07
+DEAL::Diff restrict add l1: 1.51135e-07
+DEAL::Diff restrict     l2: 4.39691e-07
+DEAL::Diff restrict add l2: 4.99465e-07
+DEAL::Diff restrict     l3: 9.43038e-07
+DEAL::Diff restrict add l3: 1.07123e-06
+DEAL::Diff restrict     l4: 1.06518e-06
+DEAL::Diff restrict add l4: 1.22748e-06
+DEAL::Diff restrict     l5: 1.29055e-06
+DEAL::Diff restrict add l5: 1.51964e-06
+DEAL::Diff restrict     l6: 1.36762e-06
+DEAL::Diff restrict add l6: 1.82467e-06
+DEAL::
+DEAL::FE: FESystem<3>[FE_Q<3>(2)^2]
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 6.46984e-08
+DEAL::Diff prolongate   l2: 2.68654e-07
+DEAL::Diff restrict     l1: 3.14590e-07
+DEAL::Diff restrict add l1: 3.14590e-07
+DEAL::Diff restrict     l2: 9.87299e-07
+DEAL::Diff restrict add l2: 1.06546e-06
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_07.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_07.cc
new file mode 100644 (file)
index 0000000..a095a15
--- /dev/null
@@ -0,0 +1,175 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree by comparison with MGTransferPrebuilt on a
+// series of meshes with adaptive meshes for FE_DGQLegendre (except for the
+// different element the same test as transfer_matrix_free_05)
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_dgq.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_DGQLegendre<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+  unsigned int sizes[] = {1, 2, 3};
+  for (unsigned int cycle = 0; cycle < sizeof(sizes) / sizeof(unsigned int);
+       ++cycle)
+    {
+      unsigned int n_refinements = 0;
+      unsigned int n_subdiv      = sizes[cycle];
+      if (n_subdiv > 1)
+        while (n_subdiv % 2 == 0)
+          {
+            n_refinements += 1;
+            n_subdiv /= 2;
+          }
+      n_refinements += 3 - dim;
+      if (fe_degree < 3)
+        n_refinements += 1;
+
+      parallel::distributed::Triangulation<dim> tr(
+        MPI_COMM_WORLD,
+        Triangulation<dim>::limit_level_difference_at_vertices,
+        parallel::distributed::Triangulation<
+          dim>::construct_multigrid_hierarchy);
+      GridGenerator::subdivided_hyper_cube(tr, n_subdiv);
+      tr.refine_global(n_refinements);
+
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() < 0.5)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.3 &&
+            cell->center().norm() < 0.4)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->center().norm() > 0.33 &&
+            cell->center().norm() < 0.37)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      // build reference
+      MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+        transfer_ref;
+      transfer_ref.build(mgdof);
+
+      // build matrix-free transfer
+      MGTransferMF<dim, Number> transfer;
+      transfer.build(mgdof);
+
+      // check prolongation for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.prolongate(level, v2, v1);
+          transfer_ref.prolongate(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+
+      // check restriction for all levels using random vector
+      for (unsigned int level = 1;
+           level < mgdof.get_triangulation().n_global_levels();
+           ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> v1, v2;
+          LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+          v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+          v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+          for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+            v1.local_element(i) = random_value<double>();
+          v1_cpy = v1;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+
+          v2 = 1.;
+          v3 = 1.;
+          transfer.restrict_and_add(level, v2, v1);
+          transfer_ref.restrict_and_add(level, v3, v1_cpy);
+          v2_cpy = v2;
+          v3 -= v2_cpy;
+          deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+                  << std::endl;
+        }
+      deallog << std::endl;
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+  check<2, double>(3);
+  check<3, double>(1);
+  check<3, double>(3);
+  check<2, float>(2);
+  check<3, float>(2);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_07.with_p4est=true.with_trilinos=true.mpirun=5.output b/tests/multigrid-global-coarsening/transfer_matrix_free_07.with_p4est=true.with_trilinos=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..78dccc7
--- /dev/null
@@ -0,0 +1,259 @@
+
+DEAL::FE: FE_DGQLegendre<2>(1)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 1.17961e-15
+DEAL::Diff prolongate   l2: 2.31497e-15
+DEAL::Diff prolongate   l3: 3.30061e-15
+DEAL::Diff prolongate   l4: 3.68951e-15
+DEAL::Diff prolongate   l5: 3.01737e-15
+DEAL::Diff restrict     l1: 1.37775e-15
+DEAL::Diff restrict add l1: 1.27555e-15
+DEAL::Diff restrict     l2: 2.56074e-15
+DEAL::Diff restrict add l2: 2.68298e-15
+DEAL::Diff restrict     l3: 4.18622e-15
+DEAL::Diff restrict add l3: 4.14368e-15
+DEAL::Diff restrict     l4: 4.18475e-15
+DEAL::Diff restrict add l4: 4.36531e-15
+DEAL::Diff restrict     l5: 2.85019e-15
+DEAL::Diff restrict add l5: 2.95411e-15
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 9.09472e-16
+DEAL::Diff prolongate   l2: 2.47191e-15
+DEAL::Diff prolongate   l3: 3.78045e-15
+DEAL::Diff prolongate   l4: 4.46449e-15
+DEAL::Diff prolongate   l5: 5.14809e-15
+DEAL::Diff prolongate   l6: 4.75228e-15
+DEAL::Diff restrict     l1: 1.33689e-15
+DEAL::Diff restrict add l1: 1.27555e-15
+DEAL::Diff restrict     l2: 2.68140e-15
+DEAL::Diff restrict add l2: 2.90573e-15
+DEAL::Diff restrict     l3: 5.86300e-15
+DEAL::Diff restrict add l3: 6.12437e-15
+DEAL::Diff restrict     l4: 4.88696e-15
+DEAL::Diff restrict add l4: 5.12750e-15
+DEAL::Diff restrict     l5: 6.62644e-15
+DEAL::Diff restrict add l5: 7.00145e-15
+DEAL::Diff restrict     l6: 6.91582e-15
+DEAL::Diff restrict add l6: 6.98735e-15
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 2.75105e-15
+DEAL::Diff prolongate   l2: 6.10804e-15
+DEAL::Diff prolongate   l3: 4.90801e-15
+DEAL::Diff prolongate   l4: 6.30864e-15
+DEAL::Diff prolongate   l5: 7.18050e-15
+DEAL::Diff restrict     l1: 3.59935e-15
+DEAL::Diff restrict add l1: 3.78128e-15
+DEAL::Diff restrict     l2: 8.14600e-15
+DEAL::Diff restrict add l2: 8.34663e-15
+DEAL::Diff restrict     l3: 7.27681e-15
+DEAL::Diff restrict add l3: 7.55849e-15
+DEAL::Diff restrict     l4: 8.39312e-15
+DEAL::Diff restrict add l4: 8.53862e-15
+DEAL::Diff restrict     l5: 9.82938e-15
+DEAL::Diff restrict add l5: 1.04862e-14
+DEAL::
+DEAL::FE: FE_DGQLegendre<2>(3)
+DEAL::no. cells: 34
+DEAL::Diff prolongate   l1: 3.00914e-15
+DEAL::Diff prolongate   l2: 6.62459e-15
+DEAL::Diff prolongate   l3: 6.49387e-15
+DEAL::Diff prolongate   l4: 3.09889e-15
+DEAL::Diff restrict     l1: 3.64043e-15
+DEAL::Diff restrict add l1: 3.56656e-15
+DEAL::Diff restrict     l2: 6.57463e-15
+DEAL::Diff restrict add l2: 6.49931e-15
+DEAL::Diff restrict     l3: 6.23681e-15
+DEAL::Diff restrict add l3: 6.12739e-15
+DEAL::Diff restrict     l4: 4.53656e-15
+DEAL::Diff restrict add l4: 4.58698e-15
+DEAL::
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 2.63188e-15
+DEAL::Diff prolongate   l2: 5.48505e-15
+DEAL::Diff prolongate   l3: 8.92854e-15
+DEAL::Diff prolongate   l4: 9.11112e-15
+DEAL::Diff prolongate   l5: 6.94348e-15
+DEAL::Diff restrict     l1: 3.97198e-15
+DEAL::Diff restrict add l1: 4.05953e-15
+DEAL::Diff restrict     l2: 6.33031e-15
+DEAL::Diff restrict add l2: 6.60559e-15
+DEAL::Diff restrict     l3: 9.09159e-15
+DEAL::Diff restrict add l3: 9.07128e-15
+DEAL::Diff restrict     l4: 9.35191e-15
+DEAL::Diff restrict add l4: 9.59813e-15
+DEAL::Diff restrict     l5: 7.73956e-15
+DEAL::Diff restrict add l5: 7.73261e-15
+DEAL::
+DEAL::no. cells: 141
+DEAL::Diff prolongate   l1: 8.50986e-15
+DEAL::Diff prolongate   l2: 9.70102e-15
+DEAL::Diff prolongate   l3: 1.17234e-14
+DEAL::Diff prolongate   l4: 1.10643e-14
+DEAL::Diff restrict     l1: 9.82721e-15
+DEAL::Diff restrict add l1: 9.94130e-15
+DEAL::Diff restrict     l2: 8.95066e-15
+DEAL::Diff restrict add l2: 8.93712e-15
+DEAL::Diff restrict     l3: 1.21155e-14
+DEAL::Diff restrict add l3: 1.22089e-14
+DEAL::Diff restrict     l4: 1.12588e-14
+DEAL::Diff restrict add l4: 1.14013e-14
+DEAL::
+DEAL::FE: FE_DGQLegendre<3>(1)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 2.50686e-15
+DEAL::Diff prolongate   l2: 2.81673e-15
+DEAL::Diff restrict     l1: 4.67086e-15
+DEAL::Diff restrict add l1: 4.74158e-15
+DEAL::Diff restrict     l2: 3.52878e-15
+DEAL::Diff restrict add l2: 3.40026e-15
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 1.51799e-15
+DEAL::Diff prolongate   l2: 7.46319e-15
+DEAL::Diff prolongate   l3: 1.27085e-14
+DEAL::Diff prolongate   l4: 1.72742e-14
+DEAL::Diff prolongate   l5: 1.58362e-14
+DEAL::Diff restrict     l1: 4.27400e-15
+DEAL::Diff restrict add l1: 4.35683e-15
+DEAL::Diff restrict     l2: 1.31474e-14
+DEAL::Diff restrict add l2: 1.36291e-14
+DEAL::Diff restrict     l3: 1.97274e-14
+DEAL::Diff restrict add l3: 1.98513e-14
+DEAL::Diff restrict     l4: 2.76798e-14
+DEAL::Diff restrict add l4: 2.79761e-14
+DEAL::Diff restrict     l5: 2.40156e-14
+DEAL::Diff restrict add l5: 2.45131e-14
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 1.32337e-14
+DEAL::Diff prolongate   l2: 1.43823e-14
+DEAL::Diff prolongate   l3: 2.25930e-14
+DEAL::Diff prolongate   l4: 2.95496e-14
+DEAL::Diff restrict     l1: 2.40047e-14
+DEAL::Diff restrict add l1: 2.40260e-14
+DEAL::Diff restrict     l2: 2.30032e-14
+DEAL::Diff restrict add l2: 2.28488e-14
+DEAL::Diff restrict     l3: 3.79362e-14
+DEAL::Diff restrict add l3: 3.79409e-14
+DEAL::Diff restrict     l4: 4.92435e-14
+DEAL::Diff restrict add l4: 4.94843e-14
+DEAL::
+DEAL::FE: FE_DGQLegendre<3>(3)
+DEAL::no. cells: 1
+DEAL::
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 1.22857e-14
+DEAL::Diff prolongate   l2: 1.18723e-14
+DEAL::Diff restrict     l1: 1.20501e-14
+DEAL::Diff restrict add l1: 1.20596e-14
+DEAL::Diff restrict     l2: 9.27744e-15
+DEAL::Diff restrict add l2: 9.37465e-15
+DEAL::
+DEAL::no. cells: 223
+DEAL::Diff prolongate   l1: 2.80933e-14
+DEAL::Diff prolongate   l2: 4.15818e-14
+DEAL::Diff prolongate   l3: 2.64041e-14
+DEAL::Diff restrict     l1: 3.10527e-14
+DEAL::Diff restrict add l1: 3.08610e-14
+DEAL::Diff restrict     l2: 4.48476e-14
+DEAL::Diff restrict add l2: 4.52462e-14
+DEAL::Diff restrict     l3: 2.91624e-14
+DEAL::Diff restrict add l3: 2.91101e-14
+DEAL::
+DEAL::FE: FE_DGQLegendre<2>(2)
+DEAL::no. cells: 88
+DEAL::Diff prolongate   l1: 1.50767e-07
+DEAL::Diff prolongate   l2: 3.40269e-07
+DEAL::Diff prolongate   l3: 5.31799e-07
+DEAL::Diff prolongate   l4: 5.68538e-07
+DEAL::Diff prolongate   l5: 5.27410e-07
+DEAL::Diff restrict     l1: 1.00439e-07
+DEAL::Diff restrict add l1: 1.75118e-07
+DEAL::Diff restrict     l2: 4.36168e-07
+DEAL::Diff restrict add l2: 4.67837e-07
+DEAL::Diff restrict     l3: 5.13719e-07
+DEAL::Diff restrict add l3: 6.14205e-07
+DEAL::Diff restrict     l4: 5.48251e-07
+DEAL::Diff restrict add l4: 6.62665e-07
+DEAL::Diff restrict     l5: 3.55987e-07
+DEAL::Diff restrict add l5: 5.20885e-07
+DEAL::
+DEAL::no. cells: 250
+DEAL::Diff prolongate   l1: 1.40461e-07
+DEAL::Diff prolongate   l2: 4.13020e-07
+DEAL::Diff prolongate   l3: 7.35401e-07
+DEAL::Diff prolongate   l4: 8.37297e-07
+DEAL::Diff prolongate   l5: 8.92044e-07
+DEAL::Diff prolongate   l6: 8.41612e-07
+DEAL::Diff restrict     l1: 1.45801e-07
+DEAL::Diff restrict add l1: 1.62850e-07
+DEAL::Diff restrict     l2: 3.58578e-07
+DEAL::Diff restrict add l2: 4.84573e-07
+DEAL::Diff restrict     l3: 7.21057e-07
+DEAL::Diff restrict add l3: 9.44494e-07
+DEAL::Diff restrict     l4: 6.47760e-07
+DEAL::Diff restrict add l4: 8.41653e-07
+DEAL::Diff restrict     l5: 8.92925e-07
+DEAL::Diff restrict add l5: 1.05666e-06
+DEAL::Diff restrict     l6: 8.33874e-07
+DEAL::Diff restrict add l6: 1.00952e-06
+DEAL::
+DEAL::no. cells: 510
+DEAL::Diff prolongate   l1: 5.95223e-07
+DEAL::Diff prolongate   l2: 1.08340e-06
+DEAL::Diff prolongate   l3: 8.76501e-07
+DEAL::Diff prolongate   l4: 1.17615e-06
+DEAL::Diff prolongate   l5: 1.31783e-06
+DEAL::Diff restrict     l1: 4.69618e-07
+DEAL::Diff restrict add l1: 6.08473e-07
+DEAL::Diff restrict     l2: 1.03701e-06
+DEAL::Diff restrict add l2: 1.26830e-06
+DEAL::Diff restrict     l3: 9.65744e-07
+DEAL::Diff restrict add l3: 1.14572e-06
+DEAL::Diff restrict     l4: 1.06047e-06
+DEAL::Diff restrict add l4: 1.29914e-06
+DEAL::Diff restrict     l5: 1.24330e-06
+DEAL::Diff restrict add l5: 1.65485e-06
+DEAL::
+DEAL::FE: FE_DGQLegendre<3>(2)
+DEAL::no. cells: 15
+DEAL::Diff prolongate   l1: 5.47934e-07
+DEAL::Diff prolongate   l2: 4.76393e-07
+DEAL::Diff restrict     l1: 6.08284e-07
+DEAL::Diff restrict add l1: 7.43498e-07
+DEAL::Diff restrict     l2: 3.41055e-07
+DEAL::Diff restrict add l2: 4.04700e-07
+DEAL::
+DEAL::no. cells: 694
+DEAL::Diff prolongate   l1: 4.96241e-07
+DEAL::Diff prolongate   l2: 1.65120e-06
+DEAL::Diff prolongate   l3: 2.51597e-06
+DEAL::Diff prolongate   l4: 3.45087e-06
+DEAL::Diff prolongate   l5: 3.23786e-06
+DEAL::Diff restrict     l1: 4.77286e-07
+DEAL::Diff restrict add l1: 5.02006e-07
+DEAL::Diff restrict     l2: 1.37508e-06
+DEAL::Diff restrict add l2: 1.48051e-06
+DEAL::Diff restrict     l3: 2.58627e-06
+DEAL::Diff restrict add l3: 2.84981e-06
+DEAL::Diff restrict     l4: 3.19463e-06
+DEAL::Diff restrict add l4: 3.50298e-06
+DEAL::Diff restrict     l5: 3.15360e-06
+DEAL::Diff restrict add l5: 3.41047e-06
+DEAL::
+DEAL::no. cells: 1791
+DEAL::Diff prolongate   l1: 3.02960e-06
+DEAL::Diff prolongate   l2: 3.11031e-06
+DEAL::Diff prolongate   l3: 4.96800e-06
+DEAL::Diff prolongate   l4: 6.37747e-06
+DEAL::Diff restrict     l1: 2.79504e-06
+DEAL::Diff restrict add l1: 3.06625e-06
+DEAL::Diff restrict     l2: 2.58243e-06
+DEAL::Diff restrict add l2: 2.91690e-06
+DEAL::Diff restrict     l3: 4.58185e-06
+DEAL::Diff restrict add l3: 5.03720e-06
+DEAL::Diff restrict     l4: 5.87275e-06
+DEAL::Diff restrict add l4: 6.48746e-06
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_08.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_08.cc
new file mode 100644 (file)
index 0000000..636a47f
--- /dev/null
@@ -0,0 +1,128 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree for high polynomial degrees beyond 10 by
+// checking a linear function that gets prolongated between the mesh
+// levels. Since the function is linear, it should be exactly represented on
+// the finest level. Then also look into the result of restriction
+
+#include <deal.II/base/function_lib.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const FiniteElement<dim> &fe)
+{
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+
+  Triangulation<dim> tr(Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(tr);
+  tr.refine_global(2);
+
+  Triangulation<dim> trcoarse(
+    Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(trcoarse);
+  DoFHandler<dim> dofcoarse(trcoarse);
+  dofcoarse.distribute_dofs(fe);
+  Tensor<1, dim> exponents_monomial;
+  for (unsigned int d = 0; d < dim; ++d)
+    exponents_monomial[d] = 1;
+  LinearAlgebra::distributed::Vector<double> vrefcoarse;
+  vrefcoarse.reinit(dofcoarse.n_dofs());
+  VectorTools::interpolate(dofcoarse,
+                           Functions::Monomial<dim>(exponents_monomial),
+                           vrefcoarse);
+
+  deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+  DoFHandler<dim> mgdof(tr);
+  mgdof.distribute_dofs(fe);
+  mgdof.distribute_mg_dofs();
+
+  // build matrix-free transfer
+  MGTransferMF<dim, Number> transfer;
+  transfer.build(mgdof);
+
+  LinearAlgebra::distributed::Vector<double> vrefdouble;
+  LinearAlgebra::distributed::Vector<Number> vref;
+  AssertDimension(mgdof.n_dofs(tr.n_global_levels() - 1), mgdof.n_dofs());
+  vrefdouble.reinit(mgdof.n_dofs());
+  VectorTools::interpolate(mgdof,
+                           Functions::Monomial<dim>(exponents_monomial),
+                           vrefdouble);
+
+  vref.reinit(mgdof.n_dofs());
+  vref = vrefdouble;
+  std::vector<LinearAlgebra::distributed::Vector<Number>> vec(
+    tr.n_global_levels());
+  for (unsigned int level = 0; level < tr.n_global_levels(); ++level)
+    vec[level].reinit(mgdof.n_dofs(level));
+  vec.back() = vref;
+
+  // prolongate monomial from coarse to fine, should be exact for monomial
+  vec[0] = vrefcoarse;
+  for (unsigned int level = 1; level < tr.n_global_levels(); ++level)
+    transfer.prolongate(level, vec[level], vec[level - 1]);
+  vec.back() -= vref;
+  const Number tolerance = 1000. * std::numeric_limits<Number>::epsilon();
+  deallog << "Error after prolongation: "
+          << filter_out_small_numbers(vec.back().linfty_norm(), tolerance)
+          << std::endl;
+
+  // unfortunately, no completely trivial expression of what should happen
+  // during restriction
+  vec.back() = vref;
+  for (unsigned int level = tr.n_global_levels() - 1; level > 0; --level)
+    transfer.restrict_and_add(level, vec[level - 1], vec[level]);
+  deallog << "Norm after restriction: " << vec[0].l2_norm() << std::endl;
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  initlog();
+
+  check<2, double>(FE_DGQ<2>(3));
+  check<2, double>(FE_DGQ<2>(8));
+  check<2, double>(FE_DGQ<2>(16));
+  check<2, double>(FE_Q<2>(16));
+  check<3, double>(FE_DGQ<3>(11));
+  check<2, float>(FE_DGQ<2>(3));
+  check<2, float>(FE_DGQ<2>(8));
+  check<2, float>(FE_DGQ<2>(16));
+  check<2, float>(FE_Q<2>(16));
+  check<3, float>(FE_DGQ<3>(11));
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_08.output b/tests/multigrid-global-coarsening/transfer_matrix_free_08.output
new file mode 100644 (file)
index 0000000..bfb4799
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 34.1210
+DEAL::FE: FE_DGQ<2>(8)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 71.6678
+DEAL::FE: FE_DGQ<2>(16)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 151.607
+DEAL::FE: FE_Q<2>(16)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 133.734
+DEAL::FE: FE_DGQ<3>(11)
+DEAL::no. cells: 64
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 774.120
+DEAL::FE: FE_DGQ<2>(3)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 34.1210
+DEAL::FE: FE_DGQ<2>(8)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 71.6678
+DEAL::FE: FE_DGQ<2>(16)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 151.607
+DEAL::FE: FE_Q<2>(16)
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 133.734
+DEAL::FE: FE_DGQ<3>(11)
+DEAL::no. cells: 64
+DEAL::Error after prolongation: 0
+DEAL::Norm after restriction: 774.120
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_09.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_09.cc
new file mode 100644 (file)
index 0000000..66d6a77
--- /dev/null
@@ -0,0 +1,129 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check that MGTransferMatrixFree::clear works correctly by comparing a
+// cleared transfer system with a freshly constructed one
+#include <deal.II/base/function_lib.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const FiniteElement<dim> &fe)
+{
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  MGConstrainedDoFs         mg_constrained_dofs;
+  MGTransferMF<dim, Number> transfer;
+  Triangulation<dim> tr(Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(tr);
+  tr.refine_global(6 - dim);
+
+  // run a few different sizes...
+  for (unsigned int c = 0; c < 4; ++c)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if ((cell->center().norm() < 0.5 &&
+             (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+            (dim == 2 && cell->center().norm() > 1.2))
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      Tensor<1, dim> exponents_monomial;
+      for (unsigned int d = 0; d < dim; ++d)
+        exponents_monomial[d] = 1;
+      LinearAlgebra::distributed::Vector<double> vref;
+      vref.reinit(mgdof.n_dofs());
+      VectorTools::interpolate(mgdof,
+                               Functions::Monomial<dim>(exponents_monomial),
+                               vref);
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      const std::set<types::boundary_id> dirichlet_boundary = {0};
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof,
+                                                         dirichlet_boundary);
+
+      // build matrix-free transfer
+      transfer.clear();
+      transfer.initialize_constraints(mg_constrained_dofs);
+      transfer.build(mgdof);
+      MGTransferMF<dim, Number> transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+      MGLevelObject<LinearAlgebra::distributed::Vector<Number>> vectors(
+        0, tr.n_global_levels() - 1);
+      transfer_ref.copy_to_mg(mgdof, vectors, vref);
+      for (unsigned int level = vectors.max_level(); level > 0; --level)
+        {
+          LinearAlgebra::distributed::Vector<Number> vec2(vectors[level - 1]);
+          transfer_ref.restrict_and_add(level,
+                                        vectors[level - 1],
+                                        vectors[level]);
+          transfer.restrict_and_add(level, vec2, vectors[level]);
+          vec2 -= vectors[level - 1];
+          deallog << "Error in restriction:  " << (double)vec2.linfty_norm()
+                  << std::endl;
+        }
+
+      for (unsigned int level = 1; level < vectors.max_level(); ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> vec2(vectors[level + 1]);
+          transfer_ref.prolongate(level + 1,
+                                  vectors[level + 1],
+                                  vectors[level]);
+          transfer.prolongate(level + 1, vec2, vectors[level]);
+          vec2 -= vectors[level + 1];
+          deallog << "Error in prolongation: " << (double)vec2.linfty_norm()
+                  << std::endl;
+        }
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  initlog();
+
+  check<2, double>(FE_DGQ<2>(2));
+  check<2, double>(FE_Q<2>(2));
+  check<3, double>(FE_Q<3>(1));
+  check<2, float>(FE_Q<2>(2));
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_09.output b/tests/multigrid-global-coarsening/transfer_matrix_free_09.output
new file mode 100644 (file)
index 0000000..37eaf90
--- /dev/null
@@ -0,0 +1,205 @@
+
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 757
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 2808
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6847
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 33776
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_10.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_10.cc
new file mode 100644 (file)
index 0000000..cffc150
--- /dev/null
@@ -0,0 +1,127 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 - 2022 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check that MGTransferMatrixFree::build works correctly by comparing the
+// build on an already existing transfer system with a freshly constructed one
+#include <deal.II/base/function_lib.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const FiniteElement<dim> &fe)
+{
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  MGConstrainedDoFs         mg_constrained_dofs;
+  MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+  Triangulation<dim> tr(Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(tr);
+  tr.refine_global(6 - dim);
+
+  // run a few different sizes...
+  for (unsigned int c = 0; c < 4; ++c)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if ((cell->center().norm() < 0.5 &&
+             (cell->level() < 5 || cell->center().norm() > 0.45)) ||
+            (dim == 2 && cell->center().norm() > 1.2))
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      Tensor<1, dim> exponents_monomial;
+      for (unsigned int d = 0; d < dim; ++d)
+        exponents_monomial[d] = 1;
+      LinearAlgebra::distributed::Vector<double> vref;
+      vref.reinit(mgdof.n_dofs());
+      VectorTools::interpolate(mgdof,
+                               Functions::Monomial<dim>(exponents_monomial),
+                               vref);
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+      const std::set<types::boundary_id> dirichlet_boundary = {0};
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof,
+                                                         dirichlet_boundary);
+
+      // build matrix-free transfer
+      transfer.build(mgdof);
+      MGTransferMF<dim, Number> transfer_ref(mg_constrained_dofs);
+      transfer_ref.build(mgdof);
+      MGLevelObject<LinearAlgebra::distributed::Vector<Number>> vectors(
+        0, tr.n_global_levels() - 1);
+      transfer_ref.copy_to_mg(mgdof, vectors, vref);
+      for (unsigned int level = vectors.max_level(); level > 0; --level)
+        {
+          LinearAlgebra::distributed::Vector<Number> vec2(vectors[level - 1]);
+          transfer_ref.restrict_and_add(level,
+                                        vectors[level - 1],
+                                        vectors[level]);
+          transfer.restrict_and_add(level, vec2, vectors[level]);
+          vec2 -= vectors[level - 1];
+          deallog << "Error in restriction:  " << (double)vec2.linfty_norm()
+                  << std::endl;
+        }
+
+      for (unsigned int level = 1; level < vectors.max_level(); ++level)
+        {
+          LinearAlgebra::distributed::Vector<Number> vec2(vectors[level + 1]);
+          transfer_ref.prolongate(level + 1,
+                                  vectors[level + 1],
+                                  vectors[level]);
+          transfer.prolongate(level + 1, vec2, vectors[level]);
+          vec2 -= vectors[level + 1];
+          deallog << "Error in prolongation: " << (double)vec2.linfty_norm()
+                  << std::endl;
+        }
+    }
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  initlog();
+
+  check<2, double>(FE_DGQ<2>(2));
+  check<2, double>(FE_Q<2>(2));
+  check<3, double>(FE_Q<3>(1));
+  check<2, float>(FE_Q<2>(2));
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_10.output b/tests/multigrid-global-coarsening/transfer_matrix_free_10.output
new file mode 100644 (file)
index 0000000..37eaf90
--- /dev/null
@@ -0,0 +1,205 @@
+
+DEAL::FE: FE_DGQ<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<3>(1)
+DEAL::no. cells: 757
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 2808
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6847
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 33776
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::FE: FE_Q<2>(2)
+DEAL::no. cells: 448
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 766
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 1924
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::no. cells: 6082
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in restriction:  0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
+DEAL::Error in prolongation: 0
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_11.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_11.cc
new file mode 100644 (file)
index 0000000..3596df9
--- /dev/null
@@ -0,0 +1,145 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Check MGTransferMatrixFree and MGTransferPrebuilt for periodic boundary
+// conditions
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_tools.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const unsigned int fe_degree)
+{
+  FE_Q<dim> fe(fe_degree);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  parallel::distributed::Triangulation<dim> tr(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::hyper_cube(tr, -1, 1, true);
+  std::vector<
+    GridTools::PeriodicFacePair<typename Triangulation<dim>::cell_iterator>>
+    periodicity_vector;
+  GridTools::collect_periodic_faces(tr, 0, 1, 0, periodicity_vector);
+  GridTools::collect_periodic_faces(tr, 2, 3, 1, periodicity_vector);
+  tr.add_periodicity(periodicity_vector);
+  tr.refine_global(2);
+  deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+  DoFHandler<dim> mgdof(tr);
+  mgdof.distribute_dofs(fe);
+  mgdof.distribute_mg_dofs();
+
+  MGConstrainedDoFs mg_constrained_dofs;
+  mg_constrained_dofs.initialize(mgdof);
+
+  // build reference
+  MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>> transfer_ref(
+    mg_constrained_dofs);
+  transfer_ref.build(mgdof);
+  deallog << "Transfer matrices: " << std::endl;
+  transfer_ref.print_matrices(deallog.get_file_stream());
+  deallog << std::endl;
+
+  // build matrix-free transfer
+  MGTransferMF<dim, Number> transfer(mg_constrained_dofs);
+  transfer.build(mgdof);
+
+  // check prolongation for all levels using random vector
+  for (unsigned int level = 1;
+       level < mgdof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      LinearAlgebra::distributed::Vector<Number> v1, v2;
+      LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+      v1.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+      v2.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+      v3.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+      for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+        v1.local_element(i) = random_value<double>();
+      v1_cpy = v1;
+      transfer.prolongate(level, v2, v1);
+      transfer_ref.prolongate(level, v3, v1_cpy);
+      v2_cpy = v2;
+      v3 -= v2_cpy;
+      deallog << "Diff prolongate   l" << level << ": " << v3.l2_norm()
+              << std::endl;
+      if (v3.l2_norm() > 1e-12)
+        {
+          // On level 0, we expect the matrix-based constraints to be wrong
+          // because it cannot capture the periodicity connections with a
+          // single cell
+          v2_cpy.print(deallog.get_file_stream());
+          v3.print(deallog.get_file_stream());
+        }
+    }
+
+  // check restriction for all levels using random vector
+  for (unsigned int level = 1;
+       level < mgdof.get_triangulation().n_global_levels();
+       ++level)
+    {
+      LinearAlgebra::distributed::Vector<Number> v1, v2;
+      LinearAlgebra::distributed::Vector<double> v1_cpy, v2_cpy, v3;
+      v1.reinit(mgdof.locally_owned_mg_dofs(level), MPI_COMM_WORLD);
+      v2.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+      v3.reinit(mgdof.locally_owned_mg_dofs(level - 1), MPI_COMM_WORLD);
+      for (unsigned int i = 0; i < v1.locally_owned_size(); ++i)
+        v1.local_element(i) = random_value<double>();
+      v1_cpy = v1;
+      transfer.restrict_and_add(level, v2, v1);
+      transfer_ref.restrict_and_add(level, v3, v1_cpy);
+      v2_cpy = v2;
+      v3 -= v2_cpy;
+      deallog << "Diff restrict     l" << level << ": " << v3.l2_norm()
+              << std::endl;
+
+      v2 = 1.;
+      v3 = 1.;
+      transfer.restrict_and_add(level, v2, v1);
+      transfer_ref.restrict_and_add(level, v3, v1_cpy);
+      v2_cpy = v2;
+      v3 -= v2_cpy;
+      deallog << "Diff restrict add l" << level << ": " << v3.l2_norm()
+              << std::endl;
+    }
+  deallog << std::endl;
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2, double>(1);
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_11.with_p4est=true.with_trilinos=true.mpirun=1.output b/tests/multigrid-global-coarsening/transfer_matrix_free_11.with_p4est=true.with_trilinos=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..49963ec
--- /dev/null
@@ -0,0 +1,64 @@
+
+DEAL::FE: FE_Q<2>(1)
+DEAL::no. cells: 16
+DEAL::Transfer matrices: 
+Level 0
+(3,3) 0.250000
+(5,3) 0.500000
+(7,3) 0.500000
+(8,3) 1.00000
+
+Level 1
+(3,3) 0.250000
+(3,5) 0.250000
+(3,7) 0.250000
+(3,8) 0.250000
+(5,3) 0.500000
+(5,7) 0.500000
+(7,3) 0.500000
+(7,5) 0.500000
+(8,3) 1.00000
+(10,3) 0.250000
+(10,5) 0.250000
+(10,7) 0.250000
+(10,8) 0.250000
+(12,5) 0.500000
+(12,8) 0.500000
+(13,3) 0.500000
+(13,5) 0.500000
+(14,5) 1.00000
+(16,3) 0.250000
+(16,5) 0.250000
+(16,7) 0.250000
+(16,8) 0.250000
+(17,3) 0.500000
+(17,7) 0.500000
+(19,7) 0.500000
+(19,8) 0.500000
+(20,7) 1.00000
+(21,3) 0.250000
+(21,5) 0.250000
+(21,7) 0.250000
+(21,8) 0.250000
+(22,5) 0.500000
+(22,8) 0.500000
+(23,7) 0.500000
+(23,8) 0.500000
+(24,8) 1.00000
+
+DEAL::
+DEAL::Diff prolongate   l1: 0.823013
+Process #0
+Local range: [0, 9), global size: 9
+Vector data:
+0.000e+00 0.000e+00 0.000e+00 7.984e-01 0.000e+00 7.984e-01 0.000e+00 7.984e-01 7.984e-01 
+Process #0
+Local range: [0, 9), global size: 9
+Vector data:
+0.000e+00 0.000e+00 0.000e+00 -5.988e-01 0.000e+00 -3.992e-01 0.000e+00 -3.992e-01 0.000e+00 
+DEAL::Diff prolongate   l2: 0
+DEAL::Diff restrict     l1: 0.555735
+DEAL::Diff restrict add l1: 0.555735
+DEAL::Diff restrict     l2: 0
+DEAL::Diff restrict add l2: 0
+DEAL::
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_12.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_12.cc
new file mode 100644 (file)
index 0000000..6b4cf76
--- /dev/null
@@ -0,0 +1,131 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2018 - 2019 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Similar to transfer_matrix_free_08 but using a system of equations: high
+// polynomial degrees beyond 10 that are compared against a linear function
+// that gets prolongated between the mesh levels. Since the function is
+// linear, it should be exactly represented on the finest level. Then also
+// look into the result of restriction
+
+#include <deal.II/base/function_lib.h>
+
+#include <deal.II/fe/fe_dgq.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/fe/fe_system.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/tria.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include <deal.II/numerics/vector_tools.h>
+
+#include "../tests.h"
+
+
+template <int dim, typename Number>
+void
+check(const FiniteElement<dim> &fe_scalar)
+{
+  FESystem<dim> fe(fe_scalar, dim);
+  deallog << "FE: " << fe.get_name() << std::endl;
+
+  // run a few different sizes...
+
+  Triangulation<dim> tr(Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(tr);
+  tr.refine_global(2);
+
+  Triangulation<dim> trcoarse(
+    Triangulation<dim>::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(trcoarse);
+  DoFHandler<dim> dofcoarse(trcoarse);
+  dofcoarse.distribute_dofs(fe);
+  Tensor<1, dim> exponents_monomial;
+  for (unsigned int d = 0; d < dim; ++d)
+    exponents_monomial[d] = 1;
+  LinearAlgebra::distributed::Vector<double> vrefcoarse;
+  vrefcoarse.reinit(dofcoarse.n_dofs());
+  VectorTools::interpolate(dofcoarse,
+                           Functions::Monomial<dim>(exponents_monomial, dim),
+                           vrefcoarse);
+
+  deallog << "no. cells: " << tr.n_global_active_cells() << std::endl;
+
+  DoFHandler<dim> mgdof(tr);
+  mgdof.distribute_dofs(fe);
+  mgdof.distribute_mg_dofs();
+
+  // build matrix-free transfer
+  MGTransferMF<dim, Number> transfer;
+  transfer.build(mgdof);
+
+  LinearAlgebra::distributed::Vector<double> vrefdouble;
+  LinearAlgebra::distributed::Vector<Number> vref;
+  AssertDimension(mgdof.n_dofs(tr.n_global_levels() - 1), mgdof.n_dofs());
+  vrefdouble.reinit(mgdof.n_dofs());
+  VectorTools::interpolate(mgdof,
+                           Functions::Monomial<dim>(exponents_monomial, dim),
+                           vrefdouble);
+
+  vref.reinit(mgdof.n_dofs());
+  vref = vrefdouble;
+  std::vector<LinearAlgebra::distributed::Vector<Number>> vec(
+    tr.n_global_levels());
+  for (unsigned int level = 0; level < tr.n_global_levels(); ++level)
+    vec[level].reinit(mgdof.n_dofs(level));
+  vec.back() = vref;
+
+  // prolongate monomial from coarse to fine, should be exact for monomial
+  vec[0] = vrefcoarse;
+  for (unsigned int level = 1; level < tr.n_global_levels(); ++level)
+    transfer.prolongate(level, vec[level], vec[level - 1]);
+  vec.back() -= vref;
+  const Number tolerance = 1000. * std::numeric_limits<Number>::epsilon();
+  deallog << "Error after prolongation: "
+          << filter_out_small_numbers(vec.back().linfty_norm(), tolerance)
+          << std::endl;
+
+  // unfortunately, no completely trivial expression of what should happen
+  // during restriction
+  vec.back() = vref;
+  for (unsigned int level = tr.n_global_levels() - 1; level > 0; --level)
+    transfer.restrict_and_add(level, vec[level - 1], vec[level]);
+  deallog << "Norm after restriction: " << vec[0].l2_norm() << std::endl;
+}
+
+
+int
+main(int argc, char **argv)
+{
+  // no threading in this test...
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  initlog();
+
+  check<2, double>(FE_DGQ<2>(3));
+  check<2, double>(FE_DGQ<2>(8));
+  check<2, double>(FE_DGQ<2>(16));
+  check<2, double>(FE_Q<2>(16));
+  check<3, double>(FE_DGQ<3>(11));
+  check<2, float>(FE_DGQ<2>(3));
+  check<2, float>(FE_DGQ<2>(8));
+  check<2, float>(FE_DGQ<2>(16));
+  check<2, float>(FE_Q<2>(16));
+  check<3, float>(FE_DGQ<3>(11));
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_12.output b/tests/multigrid-global-coarsening/transfer_matrix_free_12.output
new file mode 100644 (file)
index 0000000..b3cf0ec
--- /dev/null
@@ -0,0 +1,41 @@
+
+DEAL::FE: FESystem<2>[FE_DGQ<2>(3)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 48.2543
+DEAL::FE: FESystem<2>[FE_DGQ<2>(8)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 101.354
+DEAL::FE: FESystem<2>[FE_DGQ<2>(16)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 214.405
+DEAL::FE: FESystem<2>[FE_Q<2>(16)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 189.129
+DEAL::FE: FESystem<3>[FE_DGQ<3>(11)^3]
+DEAL::no. cells: 64
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 1340.82
+DEAL::FE: FESystem<2>[FE_DGQ<2>(3)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 48.2544
+DEAL::FE: FESystem<2>[FE_DGQ<2>(8)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 101.354
+DEAL::FE: FESystem<2>[FE_DGQ<2>(16)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 214.405
+DEAL::FE: FESystem<2>[FE_Q<2>(16)^2]
+DEAL::no. cells: 16
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 189.129
+DEAL::FE: FESystem<3>[FE_DGQ<3>(11)^3]
+DEAL::no. cells: 64
+DEAL::Error after prolongation: 0.00000
+DEAL::Norm after restriction: 1340.82
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_14.cc b/tests/multigrid-global-coarsening/transfer_matrix_free_14.cc
new file mode 100644 (file)
index 0000000..1c44df8
--- /dev/null
@@ -0,0 +1,94 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2016 - 2021 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// document a bug in MGLevelGlobalTransfer in 3d:
+
+/*
+An error occurred in line <341> of file
+<../source/multigrid/mg_level_global_transfer.cc> in function void
+dealii::MGLevelGlobalTransfer<dealii::LinearAlgebra::distributed::Vector<Number,
+dealii::MemorySpace::Host> >::fill_and_communicate_copy_indices(const
+dealii::DoFHandler<dh_dim, spacedim>&) [with int dim = 3; int spacedim = 3;
+Number = double] The violated condition was:
+    ::dealii::deal_II_exceptions::internals::compare_for_equality(this->copy_indices_level_mine.back().n_rows(),
+0) Additional information: Dimension 2 not equal to 0.
+*/
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+template <int dim>
+void
+check()
+{
+  parallel::distributed::Triangulation<dim> tr(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    typename parallel::distributed::Triangulation<dim>::Settings(
+      parallel::distributed::Triangulation<
+        dim>::mesh_reconstruction_after_repartitioning |
+      parallel::distributed::Triangulation<
+        dim>::construct_multigrid_hierarchy));
+
+  GridGenerator::hyper_cube(tr);
+
+  tr.refine_global(2);
+
+  // coarsen a few cells:
+  for (const auto &cell : tr.active_cell_iterators())
+    {
+      if (cell->is_artificial())
+        continue;
+      const std::string id = cell->parent()->id().to_string();
+      if (id == "0_1:0" || id == "0_1:1" || id == "0_1:2" || id == "0_1:3")
+        cell->set_coarsen_flag();
+    }
+
+  tr.execute_coarsening_and_refinement();
+
+  FE_Q<dim>                 fe(1);
+  DoFHandler<dim>           mgdof(tr);
+  MGTransferMF<dim, double> transfer_mf;
+
+  mgdof.distribute_dofs(fe);
+  mgdof.distribute_mg_dofs();
+
+  deallog << "n_dofs = " << mgdof.n_dofs() << std::endl;
+
+  transfer_mf.build(mgdof);
+
+  tr.coarsen_global();
+  deallog << "OK" << std::endl;
+}
+
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  MPILogInitAll                    all;
+
+  check<2>();
+  check<3>();
+}
diff --git a/tests/multigrid-global-coarsening/transfer_matrix_free_14.with_p4est=true.mpirun=2.output b/tests/multigrid-global-coarsening/transfer_matrix_free_14.with_p4est=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..cde307a
--- /dev/null
@@ -0,0 +1,11 @@
+
+DEAL:0::n_dofs = 9
+DEAL:0::OK
+DEAL:0::n_dofs = 84
+DEAL:0::OK
+
+DEAL:1::n_dofs = 9
+DEAL:1::OK
+DEAL:1::n_dofs = 84
+DEAL:1::OK
+
diff --git a/tests/multigrid-global-coarsening/transfer_prebuilt_04.cc b/tests/multigrid-global-coarsening/transfer_prebuilt_04.cc
new file mode 100644 (file)
index 0000000..4e2cb5d
--- /dev/null
@@ -0,0 +1,111 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2000 - 2020 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+
+// Deadlock reported by Kronbichler (github
+// https://github.com/dealii/dealii/issues/2051) with 3 processes
+// in MGTransferPrebuilt
+
+
+#include <deal.II/distributed/tria.h>
+
+#include <deal.II/dofs/dof_tools.h>
+
+#include <deal.II/fe/fe_q.h>
+
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+
+#include <deal.II/lac/la_parallel_vector.h>
+
+#include <deal.II/multigrid/mg_transfer.h>
+#include <deal.II/multigrid/mg_transfer_global_coarsening.h>
+
+#include "../tests.h"
+
+
+template <int dim>
+void
+check()
+{
+  FE_Q<dim> fe(1);
+
+  parallel::distributed::Triangulation<dim> tr(
+    MPI_COMM_WORLD,
+    Triangulation<dim>::limit_level_difference_at_vertices,
+    parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+  GridGenerator::subdivided_hyper_cube(tr, 3);
+  for (unsigned int cycle = 0; cycle < (dim == 2 ? 10 : 7); ++cycle)
+    {
+      // adaptive refinement into a circle
+      for (typename Triangulation<dim>::active_cell_iterator cell =
+             tr.begin_active();
+           cell != tr.end();
+           ++cell)
+        if (cell->is_locally_owned() && cell->vertex(0).norm() < 1e-10)
+          cell->set_refine_flag();
+      tr.execute_coarsening_and_refinement();
+
+      deallog << "no. cells: " << tr.n_global_active_cells() << " on "
+              << tr.n_global_levels() << " levels" << std::endl;
+
+      DoFHandler<dim> mgdof(tr);
+      mgdof.distribute_dofs(fe);
+      mgdof.distribute_mg_dofs();
+
+      MGConstrainedDoFs mg_constrained_dofs;
+      mg_constrained_dofs.initialize(mgdof);
+      mg_constrained_dofs.make_zero_boundary_constraints(mgdof, {0});
+
+      unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
+
+      if (0)
+        {
+          std::ofstream grid_output(
+            ("out" + Utilities::to_string(myid) + ".svg").c_str());
+          GridOut           grid_out;
+          GridOutFlags::Svg flags;
+          flags.label_level_subdomain_id = true;
+          flags.coloring = GridOutFlags::Svg::level_subdomain_id;
+          flags.convert_level_number_to_height = true;
+          grid_out.set_flags(flags);
+
+          grid_out.write_svg(tr, grid_output);
+        }
+#ifdef DEAL_II_WITH_TRILINOS
+      {
+        // MGTransferPrebuilt internally uses Trilinos matrices, so only
+        // create this if we have Trilinos
+        MGTransferPrebuilt<LinearAlgebra::distributed::Vector<double>>
+          transfer_ref(mg_constrained_dofs);
+        transfer_ref.build(mgdof);
+      }
+#endif
+      {
+        // but the matrix free transfer will work without Trilinos
+        MGTransferMF<dim, double> transfer_ref(mg_constrained_dofs);
+        transfer_ref.build(mgdof);
+      }
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi(argc, argv, 1);
+  mpi_initlog();
+
+  check<2>();
+}
diff --git a/tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=2.output b/tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=2.output
new file mode 100644 (file)
index 0000000..2df36ef
--- /dev/null
@@ -0,0 +1,11 @@
+
+DEAL::no. cells: 12 on 2 levels
+DEAL::no. cells: 15 on 3 levels
+DEAL::no. cells: 18 on 4 levels
+DEAL::no. cells: 21 on 5 levels
+DEAL::no. cells: 24 on 6 levels
+DEAL::no. cells: 27 on 7 levels
+DEAL::no. cells: 30 on 8 levels
+DEAL::no. cells: 33 on 9 levels
+DEAL::no. cells: 36 on 10 levels
+DEAL::no. cells: 39 on 11 levels
diff --git a/tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=3.output b/tests/multigrid-global-coarsening/transfer_prebuilt_04.with_p4est=true.mpirun=3.output
new file mode 100644 (file)
index 0000000..2df36ef
--- /dev/null
@@ -0,0 +1,11 @@
+
+DEAL::no. cells: 12 on 2 levels
+DEAL::no. cells: 15 on 3 levels
+DEAL::no. cells: 18 on 4 levels
+DEAL::no. cells: 21 on 5 levels
+DEAL::no. cells: 24 on 6 levels
+DEAL::no. cells: 27 on 7 levels
+DEAL::no. cells: 30 on 8 levels
+DEAL::no. cells: 33 on 9 levels
+DEAL::no. cells: 36 on 10 levels
+DEAL::no. cells: 39 on 11 levels

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.