<i>This program was contributed by Ryan Grove and Timo Heister.

This material is based upon work partially supported by National Science
Foundation grant DMS1522191 and the Computational Infrastructure in
Geodynamics initiative (CIG), through the National Science Foundation under
Award No. EAR-0949446 and The University of California-Davis.

The authors would like to thank the Isaac Newton Institute for
Mathematical Sciences, Cambridge, for support and hospitality during
the programme Melt in the Mantle where work on this tutorial was
undertaken. This work was supported by EPSRC grant no EP/K032208/1.
</i>

@dealiiTutorialDOI{10.5281/zenodo.400995,https://zenodo.org/badge/DOI/10.5281/zenodo.400995.svg}

<a name="Intro"></a>
<h1>Introduction</h1>

<h3> Stokes Problem </h3>

The purpose of this tutorial is to create an efficient linear solver for the
Stokes equation and compare it to alternative approaches.  Here, we will use
FGMRES with geometric multigrid as a preconditioner velocity block, and we
will show in the results section that this is a fundamentally better approach
than the linear solvers used in step-22 (including the scheme described in
"Possible Extensions").  Fundamentally, this is because only with multigrid it
is possible to get $O(n)$ solve time, where $n$ is the number of unknowns of
the linear system. Using the Timer class, we collect some statistics to
compare setup times, solve times, and number of iterations. We also compute
errors to make sure that what we have implemented is correct.

Let $u \in H_0^1 = \{ u \in H^1(\Omega), u|_{\partial \Omega} = 0 \}$
and $p \in L_*^2 = \{ p \in L^2(\Omega), \int_\Omega p = 0
\}$. The Stokes equations read as follows in non-dimensionalized form:

@f{eqnarray*}
 - 2 \text{div} \frac {1}{2} \left[ (\nabla \textbf{u})
 + (\nabla \textbf{u})^T\right] + \nabla p & =& f \\
 - \nabla \cdot u &=& 0
@f}

Note that we are using the deformation tensor instead of $\Delta u$ (a
detailed description of the difference between the two can be found in
step-22, but in summary, the deformation tensor is more physical as
well as more expensive).

<h3> Linear %Solver and Preconditioning Issues </h3>

The weak form of
the discrete equations naturally leads to the following linear system
for the nodal values of the velocity and pressure fields:
@f{eqnarray*}
\left(\begin{array}{cc} A & B^T \\ B & 0
\end{array}\right) \left(\begin{array}{c} U \\ P \end{array}\right) =
\left(\begin{array}{c} F \\ 0 \end{array}\right).
@f}

Our goal is to compare several solution approaches.  While step-22
solves the linear system using a "Schur complement approach" in two
separate steps, we instead attack the
block system at once using FMGRES with an efficient
preconditioner, in the spirit of the approach outlined in the "Results"
section of step-22. The idea is as follows: if we find a block
preconditioner $P$ such that the matrix

@f{eqnarray*}
\left(\begin{array}{cc} A & B^T \\ B & 0 \end{array}\right) P^{-1}
@f}

is simple, then an iterative solver with that preconditioner will
converge in a few iterations. Notice that we are doing right
preconditioning here.  Using the Schur complement $S=BA^{-1}B^T$,
we find that

@f{eqnarray*}
P^{-1} = \left(\begin{array}{cc} A & B^T \\ 0 &
 S \end{array}\right)^{-1}
@f}

is a good choice. Let $\widetilde{A^{-1}}$ be an approximation of $A^{-1}$
and $\widetilde{S^{-1}}$ of $S^{-1}$, we see
@f{eqnarray*}
P^{-1} =
\left(\begin{array}{cc} A^{-1} & 0 \\ 0 & I \end{array}\right)
\left(\begin{array}{cc} I & B^T \\ 0 & -I \end{array}\right)
\left(\begin{array}{cc} I & 0 \\ 0 & S^{-1} \end{array}\right)
\approx
\left(\begin{array}{cc} \widetilde{A^{-1}} & 0 \\ 0 & I \end{array}\right)
\left(\begin{array}{cc} I & B^T \\ 0 & -I \end{array}\right)
\left(\begin{array}{cc} I & 0 \\ 0 & \widetilde{S^{-1}} \end{array}\right).
  @f}

Since $P$ is aimed to be a preconditioner only, we shall use
the approximations on the right in the equation above.

As discussed in step-22, $-M_p^{-1}=:\widetilde{S^{-1}} \approx
S^{-1}$, where $M_p$ is the pressure mass matrix and is solved approximately by using CG
with ILU as a preconditioner, and $\widetilde{A^{-1}}$ is obtained by one of
multiple methods: solving a linear system with CG and ILU as
preconditioner, just using one application of an ILU, solving a linear
system with CG and GMG (Geometric
Multigrid as described in step-16) as a preconditioner, or just performing a single V-cycle
of GMG.

As a comparison, instead of FGMRES, we also use the direct solver
UMFPACK on the whole system to compare our results with.  If you want to use
a direct solver (like UMFPACK), the system needs to be invertible. To avoid
the one dimensional null space given by the constant pressures, we fix the first pressure unknown
 to zero. This is not necessary for the iterative solvers.


<h3> Reference Solution </h3>

The test problem is a "Manufactured Solution" (see step-7 for
details), and we choose $u=(u_1,u_2,u_3)=(2\sin (\pi x), - \pi y \cos
(\pi x),- \pi z \cos (\pi x))$ and $p = \sin (\pi x)\cos (\pi y)\sin
(\pi z)$.
We apply Dirichlet boundary conditions for the velocity on the whole
boundary of the domain $\Omega=[0,1]\times[0,1]\times[0,1]$.
To enforce the boundary conditions we can just use our reference solution.

If you look up in the deal.II manual what is needed to create a class
derived from <code>Function@<dim@></code>, you will find that this
class has numerous @p virtual functions, including
Function::value(), Function::vector_value(), Function::value_list(),
etc., all of which can be overloaded.  Different parts of deal.II
will require different ones of these particular
functions. This can be confusing at first, but luckily the only thing
you actually have to implement is @p value().  The other virtual
functions in the Function class have default
implementations inside that will call your implementation of @p value
by default.

Notice that our reference solution fulfills $\nabla \cdot u = 0$. In
addition, the pressure is chosen to have a mean value of zero.  For
the "Method of Manufactured Solutions" of step-7, we need to find $\bf
f$ such that:

@f{align*}
{\bf f} =   - 2 \text{div} \frac {1}{2} \left[ (\nabla \textbf{u}) + (\nabla \textbf{u})^T\right] + \nabla p.
@f}

Using the reference solution above, we obtain:

@f{eqnarray*}
{\bf f} &=& (2 \pi^2 \sin (\pi x),- \pi^3 y \cos(\pi
x),- \pi^3 z \cos(\pi x))\\ & & + (\pi \cos(\pi x) \cos(\pi y)
\sin(\pi z) ,- \pi \sin(\pi y) \sin(\pi x) \sin(\pi z), \pi \cos(\pi
z) \sin(\pi x) \cos(\pi y)) @f}

<h3> Computing Errors </h3>

Because we do not enforce the mean
pressure to be zero for our numerical solution in the linear system,
we need to post process the solution after solving. To do this we use
the VectorTools::compute_mean_value() function to compute the mean value
of the pressure to subtract it from the pressure.


<h3> DoF Handlers </h3>

The way we implement geometric multigrid here only executes it on the
velocity variables (i.e., the $A$ matrix described above) but not the
pressure. One could implement this in different ways, including one in
which one considers all coarse grid operations as acting on $2\times
2$ block systems where we only consider the top left
block. Alternatively, we can implement things by really only
considering a linear system on the velocity part of the overall finite
element discretization. The latter is the way we want to use here.

To implement this, one would need to be able to ask questions such as
"May I have just part of a DoFHandler?". This is not possible at the
time when this program was written, so in order to answer this request
for our needs, we simply create a separate, second DoFHandler for just the
velocities. We then build linear systems for the multigrid
preconditioner based on only this second DoFHandler, and simply
transfer the first block of (overall) vectors into corresponding
vectors for the entire second DoFHandler. To make this work, we have
to assure that the <i>order</i> in which the (velocity) degrees of freedom are
ordered in the two DoFHandler objects is the same. This is in fact the
case by first distributing degrees of freedom on both, and then using
the same sequence of DoFRenumbering operations on both.


<h3> Differences from the Step 22 tutorial </h3>

The main difference between step-56 and step-22 is that we use block
solvers instead of the Schur Complement approach used in
step-22. Details of this approach can be found under the "Block Schur
complement preconditioner" subsection of the "Possible Extensions"
section of step-22. For the preconditioner of the velocity block, we
borrow a class from <a href="https://aspect.geodynamics.org">ASPECT</a>
called @p BlockSchurPreconditioner that has the option to solve for
the inverse of $A$ or just apply one preconditioner sweep for it
instead, which provides us with an expensive and cheap approach,
respectively.
