]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Fix PBC in MGConstrainedDoFs
authorPeter Munch <peterrmuench@gmail.com>
Wed, 18 Oct 2023 19:45:07 +0000 (21:45 +0200)
committerPeter Munch <peterrmuench@gmail.com>
Thu, 19 Oct 2023 20:25:35 +0000 (22:25 +0200)
doc/news/changes/minor/20231019MunchPrietoSaavedra [new file with mode: 0644]
include/deal.II/dofs/dof_tools.h
include/deal.II/multigrid/mg_constrained_dofs.h
source/dofs/dof_tools_constraints.cc
source/dofs/dof_tools_constraints.inst.in
tests/multigrid-global-coarsening/transfer_matrix_free_11.with_p4est=true.with_trilinos=true.mpirun=1.output
tests/multigrid/constrained_dofs_05.output
tests/multigrid/mg_constraints_pbc.cc [new file with mode: 0644]
tests/multigrid/mg_constraints_pbc.output [new file with mode: 0644]
tests/multigrid/transfer_matrix_free_11.with_p4est=true.with_trilinos=true.mpirun=1.output

diff --git a/doc/news/changes/minor/20231019MunchPrietoSaavedra b/doc/news/changes/minor/20231019MunchPrietoSaavedra
new file mode 100644 (file)
index 0000000..a432826
--- /dev/null
@@ -0,0 +1,6 @@
+Fixed: There was an inconsistency between the way
+DoFTools::make_periodicity_constraints() and MGConstrainedDoFs
+set up the constraints for periodic constraints. This is fixed
+now.
+<br>
+(Peter Munch, Laura Prieto Saavedra, 2023/10/19)
index 4989fbc0d3f687291624790f275133c96b3f3951..e1dc5febd8b4888ef7e0e502e541adb2c0e1f843 100644 (file)
@@ -1163,6 +1163,46 @@ namespace DoFTools
                                const ComponentMask &component_mask     = {},
                                const number         periodicity_factor = 1.);
 
+  namespace internal
+  {
+    /**
+     * Internally used in make_periodicity_constraints.
+     *
+     * Enter constraints for periodicity into the given AffineConstraints
+     * object. this function is called when at least one of the two face
+     * iterators corresponds to an active object without further children
+     *
+     * The matrix @p transformation maps degrees of freedom from one face
+     * to another. If the DoFs on the two faces are supposed to match exactly,
+     * then the matrix so provided will be the identity matrix. if face 2 is
+     * once refined from face 1, then the matrix needs to be the interpolation
+     * matrix from a face to this particular child
+     *
+     * @note: @p face_1 is supposed to be active.
+     *
+     * @note We have to be careful not to accidentally create constraint
+     * cycles when adding periodic constraints: For example, as the
+     * corresponding testcase bits/periodicity_05 demonstrates, we can
+     * occasionally get into trouble if we already have the constraint
+     * x1 == x2 and want to insert x2 == x1. We avoid this by skipping
+     * such "identity constraints" if the opposite constraint already
+     * exists.
+     */
+    template <typename FaceIterator, typename number>
+    void
+    set_periodicity_constraints(
+      const FaceIterator                             &face_1,
+      const std_cxx20::type_identity_t<FaceIterator> &face_2,
+      const FullMatrix<double>                       &transformation,
+      AffineConstraints<number>                      &affine_constraints,
+      const ComponentMask                            &component_mask,
+      const bool                                      face_orientation,
+      const bool                                      face_flip,
+      const bool                                      face_rotation,
+      const number                                    periodicity_factor,
+      const unsigned int level = numbers::invalid_unsigned_int);
+  } // namespace internal
+
   /**
    * @}
    */
index 84e55e97818353cbb26b3d8cd2c3e589577c20c6..8e86b35c8a871026759d7702a896975cf928f069 100644 (file)
@@ -21,6 +21,8 @@
 #include <deal.II/base/mg_level_object.h>
 #include <deal.II/base/subscriptor.h>
 
+#include <deal.II/dofs/dof_tools.h>
+
 #include <deal.II/lac/affine_constraints.h>
 
 #include <deal.II/multigrid/mg_tools.h>
@@ -309,58 +311,43 @@ MGConstrainedDoFs::initialize(
           level_constraints[l].reinit(dof.locally_owned_mg_dofs(l),
                                       relevant_dofs);
         }
+    }
+
+  // TODO: currently we only consider very basic periodic constraints
+  const IdentityMatrix transformation(dof.get_fe().n_dofs_per_face());
+  const ComponentMask  component_mask;
+  const double         periodicity_factor = 1.0;
+
+  for (const auto &[first_cell, second_cell] :
+       dof.get_triangulation().get_periodic_face_map())
+    {
+      // only consider non-artificial cells
+      if (first_cell.first->is_artificial_on_level())
+        continue;
+      if (second_cell.first.first->is_artificial_on_level())
+        continue;
+
+      // consider cell pairs with the same level
+      if (first_cell.first->level() != second_cell.first.first->level())
+        continue;
+
+      DoFTools::internal::set_periodicity_constraints(
+        first_cell.first->as_dof_handler_level_iterator(dof)->face(
+          first_cell.second),
+        second_cell.first.first->as_dof_handler_level_iterator(dof)->face(
+          second_cell.first.second),
+        transformation,
+        level_constraints[first_cell.first->level()],
+        component_mask,
+        second_cell.second[0],
+        second_cell.second[1],
+        second_cell.second[2],
+        periodicity_factor,
+        first_cell.first->level());
+    }
 
-      // Loop through relevant cells and faces finding those which are periodic
-      // neighbors.
-      for (const auto &cell : dof.cell_iterators_on_level(l))
-        if (cell->is_artificial_on_level() == false)
-          for (auto f : cell->face_indices())
-            if (cell->has_periodic_neighbor(f) &&
-                cell->periodic_neighbor(f)->level() == cell->level())
-              {
-                if (cell->is_locally_owned_on_level())
-                  {
-                    Assert(
-                      cell->periodic_neighbor(f)->level_subdomain_id() !=
-                        numbers::artificial_subdomain_id,
-                      ExcMessage(
-                        "Periodic neighbor of a locally owned cell must either be owned or ghost."));
-                  }
-                // Cell is a level-ghost and its neighbor is a
-                // level-artificial cell nothing to do here
-                else if (cell->periodic_neighbor(f)->level_subdomain_id() ==
-                         numbers::artificial_subdomain_id)
-                  {
-                    Assert(cell->is_locally_owned_on_level() == false,
-                           ExcInternalError());
-                    continue;
-                  }
-
-                const unsigned int dofs_per_face =
-                  dof.get_fe(0).n_dofs_per_face(f);
-                std::vector<types::global_dof_index> dofs_1(dofs_per_face);
-                std::vector<types::global_dof_index> dofs_2(dofs_per_face);
-
-                cell->periodic_neighbor(f)
-                  ->face(cell->periodic_neighbor_face_no(f))
-                  ->get_mg_dof_indices(l, dofs_1, 0);
-                cell->face(f)->get_mg_dof_indices(l, dofs_2, 0);
-                // Store periodicity information in the level
-                // AffineConstraints object. Skip DoFs for which we've
-                // previously entered periodicity constraints already; this
-                // can happen, for example, for a vertex dof at a periodic
-                // boundary that we visit from more than one cell
-                for (unsigned int i = 0; i < dofs_per_face; ++i)
-                  if (level_constraints[l].can_store_line(dofs_2[i]) &&
-                      level_constraints[l].can_store_line(dofs_1[i]) &&
-                      !level_constraints[l].is_constrained(dofs_2[i]) &&
-                      !level_constraints[l].is_constrained(dofs_1[i]))
-                    {
-                      level_constraints[l].add_constraint(dofs_2[i],
-                                                          {{dofs_1[i], 1.}},
-                                                          0.);
-                    }
-              }
+  for (unsigned int l = min_level; l <= max_level; ++l)
+    {
       level_constraints[l].close();
 
       // Initialize with empty IndexSet of correct size
index 635d4fb3e8e468a1c4ad1d292e290f32d9c8b421..4d5aebe3581146c837ce78a5ff7ba7b82c323629 100644 (file)
@@ -1850,33 +1850,8 @@ namespace DoFTools
 
 
 
-  namespace
+  namespace internal
   {
-    /**
-     * @internal
-     *
-     * Internally used in make_periodicity_constraints.
-     *
-     * enter constraints for periodicity into the given AffineConstraints
-     * object. this function is called when at least one of the two face
-     * iterators corresponds to an active object without further children
-     *
-     * @param transformation A matrix that maps degrees of freedom from one face
-     * to another. If the DoFs on the two faces are supposed to match exactly,
-     * then the matrix so provided will be the identity matrix. if face 2 is
-     * once refined from face 1, then the matrix needs to be the interpolation
-     * matrix from a face to this particular child
-     *
-     * @precondition: face_1 is supposed to be active
-     *
-     * @note We have to be careful not to accidentally create constraint
-     * cycles when adding periodic constraints: For example, as the
-     * corresponding testcase bits/periodicity_05 demonstrates, we can
-     * occasionally get into trouble if we already have the constraint
-     * x1 == x2 and want to insert x2 == x1. We avoid this by skipping
-     * such "identity constraints" if the opposite constraint already
-     * exists.
-     */
     template <typename FaceIterator, typename number>
     void
     set_periodicity_constraints(
@@ -1888,13 +1863,16 @@ namespace DoFTools
       const bool                                      face_orientation,
       const bool                                      face_flip,
       const bool                                      face_rotation,
-      const number                                    periodicity_factor)
+      const number                                    periodicity_factor,
+      const unsigned int                              level)
     {
       static const int dim      = FaceIterator::AccessorType::dimension;
       static const int spacedim = FaceIterator::AccessorType::space_dimension;
 
+      const bool use_mg = level != numbers::invalid_unsigned_int;
+
       // we should be in the case where face_1 is active, i.e. has no children:
-      Assert(!face_1->has_children(), ExcInternalError());
+      Assert(use_mg || (!face_1->has_children()), ExcInternalError());
 
       Assert(face_1->n_active_fe_indices() == 1, ExcInternalError());
 
@@ -1909,7 +1887,7 @@ namespace DoFTools
       // If face_2 does have children, then we need to iterate over these
       // children and set periodic constraints in the inverse direction:
 
-      if (face_2->has_children())
+      if ((!use_mg) && face_2->has_children())
         {
           Assert(face_2->n_children() ==
                    GeometryInfo<dim>::max_children_per_face,
@@ -1971,8 +1949,15 @@ namespace DoFTools
       std::vector<types::global_dof_index> dofs_1(dofs_per_face);
       std::vector<types::global_dof_index> dofs_2(dofs_per_face);
 
-      face_1->get_dof_indices(dofs_1, face_1_index);
-      face_2->get_dof_indices(dofs_2, face_2_index);
+      if (use_mg)
+        face_1->get_mg_dof_indices(level, dofs_1, face_1_index);
+      else
+        face_1->get_dof_indices(dofs_1, face_1_index);
+
+      if (use_mg)
+        face_2->get_mg_dof_indices(level, dofs_2, face_2_index);
+      else
+        face_2->get_dof_indices(dofs_2, face_2_index);
 
       // If either of the two faces has an invalid dof index, stop. This is
       // so that there is no attempt to match artificial cells of parallel
@@ -2232,9 +2217,11 @@ namespace DoFTools
             }
         } /* for dofs_per_face */
     }
+  } // namespace internal
 
 
-
+  namespace
+  {
     // Internally used in make_periodicity_constraints.
     //
     // Build up a (possibly rotated) interpolation matrix that is used in
@@ -2539,30 +2526,30 @@ namespace DoFTools
             // matrix is the identity matrix.
             if (first_vector_components.empty() && matrix.m() == 0)
               {
-                set_periodicity_constraints(face_2,
-                                            face_1,
-                                            transformation,
-                                            affine_constraints,
-                                            component_mask,
-                                            face_orientation,
-                                            face_flip,
-                                            face_rotation,
-                                            periodicity_factor);
+                internal::set_periodicity_constraints(face_2,
+                                                      face_1,
+                                                      transformation,
+                                                      affine_constraints,
+                                                      component_mask,
+                                                      face_orientation,
+                                                      face_flip,
+                                                      face_rotation,
+                                                      periodicity_factor);
               }
             else
               {
                 FullMatrix<double> inverse(transformation.m());
                 inverse.invert(transformation);
 
-                set_periodicity_constraints(face_2,
-                                            face_1,
-                                            inverse,
-                                            affine_constraints,
-                                            component_mask,
-                                            face_orientation,
-                                            face_flip,
-                                            face_rotation,
-                                            periodicity_factor);
+                internal::set_periodicity_constraints(face_2,
+                                                      face_1,
+                                                      inverse,
+                                                      affine_constraints,
+                                                      component_mask,
+                                                      face_orientation,
+                                                      face_flip,
+                                                      face_rotation,
+                                                      periodicity_factor);
               }
           }
         else
@@ -2575,17 +2562,17 @@ namespace DoFTools
             // the rotation when constraining face_2 to face_1. Therefore
             // face_flip has to be toggled if face_rotation is true: In case of
             // inverted orientation, nothing has to be done.
-            set_periodicity_constraints(face_1,
-                                        face_2,
-                                        transformation,
-                                        affine_constraints,
-                                        component_mask,
-                                        face_orientation,
-                                        face_orientation ?
-                                          face_rotation ^ face_flip :
-                                          face_flip,
-                                        face_rotation,
-                                        periodicity_factor);
+            internal::set_periodicity_constraints(face_1,
+                                                  face_2,
+                                                  transformation,
+                                                  affine_constraints,
+                                                  component_mask,
+                                                  face_orientation,
+                                                  face_orientation ?
+                                                    face_rotation ^ face_flip :
+                                                    face_flip,
+                                                  face_rotation,
+                                                  periodicity_factor);
           }
       }
   }
index 6b11357f60ec352e03cf38a2ca299e3e78477b35..85174245888942fc3b2758ed90c39740f228448b 100644 (file)
@@ -30,6 +30,34 @@ for (deal_II_dimension : DIMENSIONS; deal_II_space_dimension : SPACE_DIMENSIONS;
       const FullMatrix<double> &,
       const std::vector<unsigned int> &,
       const S);
+
+    template void DoFTools::internal::set_periodicity_constraints(
+      const DoFHandler<deal_II_dimension,
+                       deal_II_space_dimension>::face_iterator &face_1,
+      const DoFHandler<deal_II_dimension,
+                       deal_II_space_dimension>::face_iterator &face_2,
+      const FullMatrix<double>                                 &transformation,
+      AffineConstraints<S> &affine_constraints,
+      const ComponentMask  &component_mask,
+      const bool            face_orientation,
+      const bool            face_flip,
+      const bool            face_rotation,
+      const S               periodicity_factor,
+      const unsigned int    level);
+
+    template void DoFTools::internal::set_periodicity_constraints(
+      const DoFHandler<deal_II_dimension,
+                       deal_II_space_dimension>::level_face_iterator &face_1,
+      const DoFHandler<deal_II_dimension,
+                       deal_II_space_dimension>::level_face_iterator &face_2,
+      const FullMatrix<double> &transformation,
+      AffineConstraints<S>     &affine_constraints,
+      const ComponentMask      &component_mask,
+      const bool                face_orientation,
+      const bool                face_flip,
+      const bool                face_rotation,
+      const S                   periodicity_factor,
+      const unsigned int        level);
 #endif
   }
 
index 49963ec9169ae8b155d61b9a8bf33d7da8f97008..3a13121d1c63229ce3e5fa76894dc3536b030358 100644 (file)
@@ -3,62 +3,62 @@ 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
+(0,0) 1.00000
+(1,0) 0.500000
+(2,0) 0.500000
+(3,0) 0.250000
 
 Level 1
+(0,0) 1.00000
+(1,0) 0.500000
+(1,1) 0.500000
+(2,0) 0.500000
+(2,2) 0.500000
+(3,0) 0.250000
+(3,1) 0.250000
+(3,2) 0.250000
 (3,3) 0.250000
-(3,5) 0.250000
-(3,7) 0.250000
-(3,8) 0.250000
+(4,1) 1.00000
+(5,1) 0.500000
 (5,3) 0.500000
-(5,7) 0.500000
+(6,2) 1.00000
+(7,2) 0.500000
 (7,3) 0.500000
-(7,5) 0.500000
 (8,3) 1.00000
+(9,0) 0.500000
+(9,1) 0.500000
+(10,0) 0.250000
+(10,1) 0.250000
+(10,2) 0.250000
 (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,2) 0.500000
 (13,3) 0.500000
-(13,5) 0.500000
-(14,5) 1.00000
+(15,0) 0.500000
+(15,2) 0.500000
+(16,0) 0.250000
+(16,1) 0.250000
+(16,2) 0.250000
 (16,3) 0.250000
-(16,5) 0.250000
-(16,7) 0.250000
-(16,8) 0.250000
+(17,1) 0.500000
 (17,3) 0.500000
-(17,7) 0.500000
-(19,7) 0.500000
-(19,8) 0.500000
-(20,7) 1.00000
+(21,0) 0.250000
+(21,1) 0.250000
+(21,2) 0.250000
 (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
+DEAL::Diff prolongate   l1: 0.866046
 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 
+8.402e-01 8.402e-01 8.402e-01 8.402e-01 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 
 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
+0.000e+00 -4.201e-01 -4.201e-01 -6.301e-01 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 1.41100
+DEAL::Diff restrict add l1: 1.41100
+DEAL::Diff restrict     l2: 5.43896e-16
+DEAL::Diff restrict add l2: 4.44089e-16
 DEAL::
index 69c842ba43eeab412ee6e34f4183baab6bee7990..22e7da9cf74a9b522b03129c44749299925e5a21 100644 (file)
@@ -8,8 +8,8 @@ DEAL::  Faces having periodic neighbors of same level:
 DEAL::    0, 2 <-> 1, 3 via periodic boundary
 DEAL::    1, 3 <-> 0, 2 via periodic boundary
 DEAL::  Constraint matrix:
-    0 1:  1.00000
-    2 3:  1.00000
+    1 0:  1.00000
+    3 2:  1.00000
 DEAL::Level 1: 
 DEAL::  Faces neighboring coarser cells:
 DEAL::  Refinement edge DoFs: {}
@@ -18,9 +18,9 @@ DEAL::  Faces having periodic neighbors of same level:
 DEAL::    0, 2 <-> 4, 5 via periodic boundary
 DEAL::    2, 6 <-> 5, 8 via periodic boundary
 DEAL::  Constraint matrix:
-    0 4:  1.00000
-    2 5:  1.00000
-    6 8:  1.00000
+    4 0:  1.00000
+    5 2:  1.00000
+    8 6:  1.00000
 DEAL::Level 2: 
 DEAL::  Faces neighboring coarser cells:
 DEAL::    0, 2 via periodic boundary
@@ -42,10 +42,10 @@ DEAL::  Faces having periodic neighbors of same level:
 DEAL::    0, 2, 4, 6 <-> 1, 3, 5, 7 via periodic boundary
 DEAL::    1, 3, 5, 7 <-> 0, 2, 4, 6 via periodic boundary
 DEAL::  Constraint matrix:
-    0 1:  1.00000
-    2 3:  1.00000
-    4 5:  1.00000
-    6 7:  1.00000
+    1 0:  1.00000
+    3 2:  1.00000
+    5 4:  1.00000
+    7 6:  1.00000
 DEAL::Level 1: 
 DEAL::  Faces neighboring coarser cells:
 DEAL::  Refinement edge DoFs: {}
@@ -56,15 +56,15 @@ DEAL::    2, 12, 6, 14 <-> 9, 16, 11, 17 via periodic boundary
 DEAL::    4, 6, 18, 20 <-> 10, 11, 22, 23 via periodic boundary
 DEAL::    6, 14, 20, 24 <-> 11, 17, 23, 26 via periodic boundary
 DEAL::  Constraint matrix:
-    0 8:  1.00000
-    2 9:  1.00000
-    4 10:  1.00000
-    6 11:  1.00000
-    12 16:  1.00000
-    14 17:  1.00000
-    18 22:  1.00000
-    20 23:  1.00000
-    24 26:  1.00000
+    8 0:  1.00000
+    9 2:  1.00000
+    10 4:  1.00000
+    11 6:  1.00000
+    16 12:  1.00000
+    17 14:  1.00000
+    22 18:  1.00000
+    23 20:  1.00000
+    26 24:  1.00000
 DEAL::Level 2: 
 DEAL::  Faces neighboring coarser cells:
 DEAL::    0, 2, 4, 6 via periodic boundary
diff --git a/tests/multigrid/mg_constraints_pbc.cc b/tests/multigrid/mg_constraints_pbc.cc
new file mode 100644 (file)
index 0000000..cb23f82
--- /dev/null
@@ -0,0 +1,91 @@
+/* ---------------------------------------------------------------------
+ *
+ * Copyright (C) 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 that DoFTools::make_periodicity_constraints() and MGConstrainedDoFs
+ * creates the same constrains for periodic constraints in the case of
+ * globally refined meshes.
+ */
+
+#include <deal.II/dofs/dof_handler.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_in.h>
+#include <deal.II/grid/grid_tools.h>
+
+#include <deal.II/multigrid/mg_constrained_dofs.h>
+
+#include "../tests.h"
+
+using namespace dealii;
+
+int
+main()
+{
+  initlog();
+
+  const unsigned int dim           = 2;
+  const unsigned int n_refinements = 2;
+
+  Triangulation<dim> tria(
+    Triangulation<dim>::MeshSmoothing::limit_level_difference_at_vertices);
+  GridGenerator::hyper_cube(tria, 0, 1, true);
+
+  std::vector<
+    GridTools::PeriodicFacePair<typename Triangulation<dim>::cell_iterator>>
+    periodic_faces;
+
+  GridTools::collect_periodic_faces(tria, 0, 1, 0, periodic_faces);
+
+  tria.add_periodicity(periodic_faces);
+  tria.refine_global(n_refinements);
+
+  DoFHandler<dim> dof_handler(tria);
+  dof_handler.distribute_dofs(FE_Q<dim>(1));
+  dof_handler.distribute_mg_dofs();
+
+  MGConstrainedDoFs mg_constraints;
+  mg_constraints.initialize(dof_handler);
+
+  const auto &af_level = mg_constraints.get_level_constraints(n_refinements);
+
+  AffineConstraints<double> af;
+  DoFTools::make_periodicity_constraints<dim, dim, double>(
+    dof_handler, 0, 1, 0, af);
+
+  for (unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
+    {
+      Assert(af_level.is_constrained(i) == af.is_constrained(i),
+             ExcInternalError());
+
+      if (af_level.is_constrained(i) == false)
+        continue;
+
+      Assert(*af_level.get_constraint_entries(i) ==
+               *af.get_constraint_entries(i),
+             ExcInternalError());
+    }
+
+#if 0
+  af_level.print(std::cout);
+  std::cout << std::endl;
+  af.print(std::cout);
+  std::cout << std::endl;
+#endif
+
+  deallog << "OK!" << std::endl;
+}
diff --git a/tests/multigrid/mg_constraints_pbc.output b/tests/multigrid/mg_constraints_pbc.output
new file mode 100644 (file)
index 0000000..5cfb783
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL::OK!
index 49963ec9169ae8b155d61b9a8bf33d7da8f97008..ac694e0756f40824c8930531ab3ddd4449ed1a45 100644 (file)
@@ -3,62 +3,62 @@ 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
+(0,0) 1.00000
+(1,0) 0.500000
+(2,0) 0.500000
+(3,0) 0.250000
 
 Level 1
+(0,0) 1.00000
+(1,0) 0.500000
+(1,1) 0.500000
+(2,0) 0.500000
+(2,2) 0.500000
+(3,0) 0.250000
+(3,1) 0.250000
+(3,2) 0.250000
 (3,3) 0.250000
-(3,5) 0.250000
-(3,7) 0.250000
-(3,8) 0.250000
+(4,1) 1.00000
+(5,1) 0.500000
 (5,3) 0.500000
-(5,7) 0.500000
+(6,2) 1.00000
+(7,2) 0.500000
 (7,3) 0.500000
-(7,5) 0.500000
 (8,3) 1.00000
+(9,0) 0.500000
+(9,1) 0.500000
+(10,0) 0.250000
+(10,1) 0.250000
+(10,2) 0.250000
 (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,2) 0.500000
 (13,3) 0.500000
-(13,5) 0.500000
-(14,5) 1.00000
+(15,0) 0.500000
+(15,2) 0.500000
+(16,0) 0.250000
+(16,1) 0.250000
+(16,2) 0.250000
 (16,3) 0.250000
-(16,5) 0.250000
-(16,7) 0.250000
-(16,8) 0.250000
+(17,1) 0.500000
 (17,3) 0.500000
-(17,7) 0.500000
-(19,7) 0.500000
-(19,8) 0.500000
-(20,7) 1.00000
+(21,0) 0.250000
+(21,1) 0.250000
+(21,2) 0.250000
 (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
+DEAL::Diff prolongate   l1: 0.866046
 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 
+8.402e-01 8.402e-01 8.402e-01 8.402e-01 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 
 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
+0.000e+00 -4.201e-01 -4.201e-01 -6.301e-01 0.000e+00 0.000e+00 0.000e+00 0.000e+00 0.000e+00 
+DEAL::Diff prolongate   l2: 0.00000
+DEAL::Diff restrict     l1: 1.41100
+DEAL::Diff restrict add l1: 1.41100
+DEAL::Diff restrict     l2: 6.66134e-16
+DEAL::Diff restrict add l2: 6.28037e-16
 DEAL::

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.