<br>

<i>This program was contributed by Daniel Arndt and Matthias Maier.</i>
<a name="Intro"></a>
<h1>Introduction</h1>

In this example we present how to use periodic boundary conditions in
deal.II. Periodic boundary conditions are algebraic constraints that
typically occur in computations on representative regions of a larger
domain that repeat in one or more directions.

An example is the simulation of the electronic structure of photonic
crystals, because they have a lattice-like structure and, thus, it often
suffices to do the actual computation on only one box of the lattice. To
be able to proceed this way one has to assume that the computation can be
periodically extended to the other boxes; this requires the solution to
have a periodic structure.

<a name="Procedure"></a>
<h1>Procedure</h1>

deal.II provides a number of high level entry points to impose periodic
boundary conditions.
The general approach to apply periodic boundary conditions consists of
three steps (see also the
@ref GlossPeriodicConstraints "Glossary entry on periodic boundary conditions"):
-# Create a mesh
-# Identify those pairs of faces on different parts of the boundary across which
   the solution should be symmetric, using GridTools::collect_periodic_faces()
-# Add the periodicity information to the mesh
   using parallel::distributed::Triangulation::add_periodicity()
-# Add periodicity constraints using DoFTools::make_periodicity_constraints()

The second and third step are necessary for distributed meshes
to ensure that cells on opposite sides of the domain but connected by periodic
faces are part of the ghost layer if one of them is stored on the local processor.
If the Triangulation is not a parallel::distributed::Triangulation,
these steps have to be omitted.

The first step consists of collecting matching periodic faces and storing them in
a <code>std::vector</code> of GridTools::PeriodicFacePair. This is done with the
function GridTools::collect_periodic_faces() that can be invoked for example
like this:
@code
GridTools::collect_periodic_faces(dof_handler,
                                  b_id1,
                                  b_id2,
                                  direction,
                                  matched_pairs,
                                  offset = <default value>,
                                  matrix = <default value>,
                                  first_vector_components = <default value>);
@endcode

This call loops over all faces of the container dof_handler on the opposing
boundaries with boundary indicator @p b_id1 and @p b_id2,
respecitvely. If $\text{vertices}_{1/2}$ are the vertices of $\text{face}_{1/2}$,
it matches pairs of faces (and dofs) such that the difference between $\text{vertices}_2$
and $matrix\cdot \text{vertices}_1+\text{offset}$ vanishes in every component apart from direction
and stores the resulting pairs with associated data in @p matched_pairs. (See
GridTools::orthogonal_equality() for detailed information about the
matching process.)

Consider, for example, the colored unit square $\Omega=[0,1]^2$ with boundary
indicator 0 on the left, 1 on the right, 2 on the bottom and 3 on the top
faces. Then,
@code
GridTools::collect_periodic_faces(dof_handler,
                                  /*b_id1*/ 0,
                                  /*b_id2*/ 1,
                                  /*direction*/ 0,
                                  matched_pairs);
@endcode
would yield periodicity constraints such that $u(0,y)=u(1,y)$ for all
$y\in[0,1]$.

If we instead consider the parallelogram given by the convex hull of
$(0,0)$, $(1,1)$, $(1,2)$, $(0,1)$ we can achieve the constraints
$u(0,y)=u(1,y+1)$ by specifying an @p offset:
@code
GridTools::collect_periodic_faces(dof_handler,
                                  /*b_id1*/ 0,
                                  /*b_id2*/ 1,
                                  /*direction*/ 0,
                                  matched_pairs,
                                  Tensor<1, 2>(0.,1.));
@endcode
or
@code
GridTools::collect_periodic_faces(dof_handler,
                                  /*b_id1*/ 0,
                                  /*b_id2*/ 1,
                                  /*arbitrary direction*/ 0,
                                  matched_pairs,
                                  Tensor<1, 2>(1.,1.));
@endcode

The resulting @p matched_pairs can be used in
DoFTools::make_periodicity_constraints for populating a ConstraintMatrix
with periodicity constraints:
@code
DoFTools::make_periodicity_constraints(matched_pairs, constraints);
@endcode

Apart from this high level interface there are also variants of
DoFTools::make_periodicity_constraints available that combine those two
steps (see the variants of DofTools::make_periodicity_constraints).

There is also a low level interface to
DoFTools::make_periodicity_constraints if more flexibility is needed. The
low level variant allows to directly specify two faces that shall be
constrained:
@code
using namespace DoFTools;
make_periodicity_constraints(face_1,
                             face_2,
                             constraint_matrix,
                             component_mask = <default value>;
                             face_orientation = <default value>,
                             face_flip = <default value>,
                             face_rotation = <default value>,
                             matrix = <default value>);
@endcode
Here, we need to specify the orientation of the two faces using
@p face_orientation, @p face_flip and @p face_orientation. For a closer description
have a look at the documentation of DoFTools::make_periodicity_constraints.
The remaining parameters are the same as for the high level interface apart
from the self-explaining @p component_mask and @p constraint_matrix.

<a name="problem"></a>
<h1>A practical example</h1>

In the following, we show how to use the above functions in a more involved
example. The task is to enforce rotated periodicity constraints for the
velocity component of a Stokes flow.

On a quarter-circle defined by $\Omega=\{{\bf x}\in(0,1)^2:\|{\bf x}\|\in (0.5,1)\}$ we are
going to solve the Stokes problem
@f{eqnarray*}
  -\Delta \; \textbf{u} + \nabla p &=& (\exp(-100*\|{\bf x}-(.75,0.1)^T\|^2),0)^T, \\
  -\textrm{div}\;  \textbf{u}&=&0,\\
  \textbf{u}|_{\Gamma_1}&=&{\bf 0},
@f}
where the boundary $\Gamma_1$ is defined as $\Gamma_1:=\{x\in \partial\Omega: \|x\|\in\{0.5,1\}\}$.
For the remaining parts of the boundary we are going to use periodic boundary conditions, i.e.
@f{align*}
  u_x(0,\nu)&=-u_y(\nu,0)&\nu&\in[0,1]\\
  u_y(0,\nu)&=u_x(\nu,0)&\nu&\in[0,1].
@f}
