# [deal.II] multiply constrained dofs (hanging nodes+periodic) fails a simple test case

```Hello dealii-team,

I have created a failing test case in serial when hanging nodes+periodic
constraints are mixed. ```
```
*The algorithm of the test is follows: (attached *
*minimalExampleHangingNodesPeriodicConstraintsBug.cc)*

1) Create a hypercube (-20,20) with origin at the center

2) Set periodic boundary conditions on the hypercube

3) Perform two levels of mesh refinement:- a) one step uniform refinement
hypercube to get 8 cells ,and b) then pick one of the 8 cells and refine
only that cell which creates hanging nodes on the faces. Finally I get 15
cells (see attached image).

4) Create two constraintMatrices: *constraints* and
*onlyHangingNodeConstraints.*
*                constraints:* both hanging node and periodic constraints
*onlyHangingNodeConstraints:* just hanging node constraints

5) Create two nodal vectors vec1 and vec2 with nodal value =
nodal_coordinate.norm(). Set and distribute vec1 using  *constraints. *Set
and distribute vec2 using *onlyHangingNodeConstraints.*

6) Print l2 norm of vec1 and vec2.

*The issue:*

Since the nodal value = nodal_coordinate.norm() is intrinsically periodic
(the domain being a hypercube with origin at the center), I would expect
vec1 and vec2 to have the same l2 norm. However I get different l2 norm
values:
L2 Norm vec1 (distributed using combined constraints): 178.494
L2 Norm vec2 (distributed using only hanging node constraints): 176.271

If I modify step 3) to: a)  two step uniform refinement hypercube to get 64
cells ,and b) then pick one of the interior cells and refine only that cell
which creates hanging nodes only in the interior. Total (71 cells). The l2
norm of vec1 and vec2 matches in this case:
L2 Norm vec1 (distributed using combined constraints): 278.505
L2 Norm vec2 (distributed using only hanging node constraints): 278.505

Thanks,
Sambit

--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see
---
You received this message because you are subscribed to the Google Groups
"deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email
```
```//Include all deal.II header file
#include <deal.II/base/function.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/timer.h>
#include <deal.II/base/table.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/constraint_matrix.h>
#include <deal.II/fe/fe_system.h>
#include <deal.II/fe/fe_q.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/mapping_q1.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/vector_tools.h>
#include <deal.II/base/tensor_function.h>
#include <deal.II/base/point.h>
#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/utilities.h>
#include <deal.II/lac/lapack_full_matrix.h>
#include <deal.II/numerics/matrix_tools.h>
#include <deal.II/numerics/error_estimator.h>
#include <deal.II/base/parameter_handler.h>
#include <deal.II/grid/grid_refinement.h>
#include <deal.II/grid/tria_boundary_lib.h>
#include <deal.II/grid/grid_tools.h>
#include <deal.II/grid/grid_in.h>
#include <deal.II/grid/grid_out.h>
#include <deal.II/dofs/dof_renumbering.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/solver_gmres.h>
#include <deal.II/lac/solver_bicgstab.h>
#include <deal.II/lac/precondition.h>
#include <deal.II/distributed/tria.h>
#include <deal.II/lac/parallel_vector.h>
#include <deal.II/matrix_free/matrix_free.h>
#include <deal.II/matrix_free/fe_evaluation.h>
#include <deal.II/lac/slepc_solver.h>
#include <deal.II/base/config.h>
#include <deal.II/base/smartpointer.h>
#include <fstream>
#include <iostream>

using namespace dealii;
int main (int argc, char *argv[])
{
Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv);

const double L=20;
Triangulation<3,3> triangulation;
GridGenerator::hyper_cube (triangulation, -L, L);

//mark faces
typename Triangulation<3,3>::active_cell_iterator cell = triangulation.begin_active(), endc = triangulation.end();
for(; cell!=endc; ++cell)
{
for(unsigned int f=0; f < GeometryInfo<3>::faces_per_cell; ++f)
{
const Point<3> face_center = cell->face(f)->center();
if(cell->face(f)->at_boundary())
{
if (std::abs(face_center[0]-L)<1.0e-5)
cell->face(f)->set_boundary_id(1);
else if (std::abs(face_center[0]+L)<1.0e-5)
cell->face(f)->set_boundary_id(2);
else if (std::abs(face_center[1]-L)<1.0e-5)
cell->face(f)->set_boundary_id(3);
else if (std::abs(face_center[1]+L)<1.0e-5)
cell->face(f)->set_boundary_id(4);
else if (std::abs(face_center[2]-L)<1.0e-5)
cell->face(f)->set_boundary_id(5);
else if (std::abs(face_center[2]+L)<1.0e-5)
cell->face(f)->set_boundary_id(6);
}
}
}

std::vector<GridTools::PeriodicFacePair<typename Triangulation<3,3>::cell_iterator> > periodicity_vector;
for (int i = 0; i < 3; ++i)
{
GridTools::collect_periodic_faces(triangulation, /*b_id1*/ 2*i+1, /*b_id2*/ 2*i+2,/*direction*/ i, periodicity_vector);
}
std::cout << "Periodic Facepairs size: " << periodicity_vector.size() << std::endl;

//FIXME: two cases of mesh refinement, both having two levels of refinement to create hanging nodes
//Case 0 which has hanging node constraint on periodic face is the buggy case
//Case 1 which has hanging node constraints in the interior works fine
const unsigned int Case=0;

if (Case==0)
{
triangulation.refine_global(1);
//pick the first cell and refine
cell = triangulation.begin_active();
cell->set_refine_flag();
triangulation.execute_coarsening_and_refinement();
}
else if (Case==1)
{
triangulation.refine_global(2);
//pick an interior cell and refine again
cell = triangulation.begin_active();
endc =  triangulation.end();
for (; cell!=endc; ++cell)
{
Point<3> cellCentroid=cell->center();

if (std::fabs(cellCentroid[0]-L/4.0)<1e-5
&& std::fabs(cellCentroid[1]-L/4.0)<1e-5
&& std::fabs(cellCentroid[2]-L/4.0)<1e-5)
cell->set_refine_flag();

}
triangulation.execute_coarsening_and_refinement();
}

std::cout << "number of elements: "
<< triangulation.n_global_active_cells()
<< std::endl;
/////

FESystem<3> FE(FE_Q<3>(QGaussLobatto<1>(2)), 1); //linear shape function
DoFHandler<3> dofHandler (triangulation);
dofHandler.distribute_dofs(FE);

///creating combined constraint matrix
ConstraintMatrix constraints;
constraints.clear();
DoFTools::make_hanging_node_constraints(dofHandler, constraints);
std::vector<GridTools::PeriodicFacePair<typename DoFHandler<3>::cell_iterator> > periodicity_vectorDof;
for (int i = 0; i < 3; ++i)
{
GridTools::collect_periodic_faces(dofHandler, /*b_id1*/ 2*i+1, /*b_id2*/ 2*i+2,/*direction*/ i, periodicity_vectorDof);
}
DoFTools::make_periodicity_constraints<DoFHandler<3> >(periodicity_vectorDof, constraints);
constraints.close();

std::cout<< "size of constraint matrix: "<< constraints.n_constraints()<<std::endl;
std::cout<< "printing constraint matrix ...."<<std::endl;
constraints.print(std::cout);

///create only hanging node constraint matrix
ConstraintMatrix onlyHangingNodeConstraints;onlyHangingNodeConstraints.clear();
DoFTools::make_hanging_node_constraints(dofHandler, onlyHangingNodeConstraints);
onlyHangingNodeConstraints.close();

Vector<double> vec1;
vec1.reinit(dofHandler.n_dofs());
vec1=0;

Vector<double> vec2;
vec2.reinit(dofHandler.n_dofs());
vec2=0;

const unsigned int vertices_per_cell=GeometryInfo<3>::vertices_per_cell;
std::vector<bool> vertex_touched(dofHandler.get_triangulation().n_vertices(),
false);

DoFHandler<3>::active_cell_iterator
cellDof = dofHandler.begin_active(),
endcDof = dofHandler.end();
for (; cellDof!=endcDof; ++cellDof)
for (unsigned int i=0; i<vertices_per_cell; ++i)
{
const unsigned global_vertex_no = cellDof->vertex_index(i);

if (vertex_touched[global_vertex_no])
continue;
vertex_touched[global_vertex_no]=true;
Point<3> nodalCoor = cellDof->vertex(i);

const unsigned int globalDofIndex=cellDof->vertex_dof_index(i,0);

if(!constraints.is_constrained(globalDofIndex))
vec1[globalDofIndex]=nodalCoor.norm();

if(!onlyHangingNodeConstraints.is_constrained(globalDofIndex))
vec2[globalDofIndex]=nodalCoor.norm();
}

constraints.distribute(vec1);
std::cout<<"L2 Norm vec1 (distributed using combined constraints): "<<vec1.l2_norm()<<std::endl;

onlyHangingNodeConstraints.distribute(vec2);
std::cout<<"L2 Norm vec2 (distributed using only hanging node constraints): "<<vec2.l2_norm()<<std::endl;
}
```