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

In this program, we will mainly consider two aspects:
<ol>
  <li> Verification of correctness of the program and generation of convergence
  tables;
  <li> Non-homogeneous Neumann boundary conditions for the Helmholtz equation.
</ol>
Besides these topics, again a variety of improvements and tricks will be
shown.


<h3>Verification of correctness</h3>

There has probably never been a
non-trivial finite element program that worked right from the start. It is
therefore necessary to find ways to verify whether a computed solution is
correct or not. Usually, this is done by choosing the set-up of a simulation
in such a way that we know the exact continuous solution and evaluate the difference
between continuous and computed discrete solution. If this difference
converges to zero with the right order of convergence, this is already a good
indication of correctness, although there may be other sources of error
persisting which have only a small contribution to the total error or are of
higher order. In the context of finite element simulations, this technique
of picking the solution by choosing appropriate right hand sides and
boundary conditions
is often called the <i>Method of Manufactured Solution</i>.

In this example, we will not go into the theories of systematic software
verification which is a very complicated problem. Rather we will demonstrate
the tools which deal.II can offer in this respect. This is basically centered
around the functionality of a single function, VectorTools::integrate_difference().
This function computes the difference between a given continuous function and
a finite element field in various norms on each cell.
Of course, like with any other integral, we can only evaluate these norms using quadrature formulas;
the choice of the right quadrature formula is therefore crucial to the
accurate evaluation of the error. This holds in particular for the $L_\infty$
norm, where we evaluate the maximal deviation of numerical and exact solution
only at the quadrature points; one should then not try to use a quadrature
rule whose evaluation occurs only at points where
[super-convergence](https://en.wikipedia.org/wiki/Superconvergence) might occur, such as
the Gauss points of the lowest-order Gauss quadrature formula for which the
integrals in the assembly of the matrix is correct (e.g., for linear elements,
do not use the QGauss(2) quadrature formula). In fact, this is generally good
advice also for the other norms: if your quadrature points are fortuitously
chosen at locations where the error happens to be particularly small due to
superconvergence, the computed error will look like it is much smaller than
it really is and may even suggest a higher convergence order. Consequently,
we will choose a different quadrature formula for the integration of these
error norms than for the assembly of the linear system.

The function VectorTools::integrate_difference() evaluates the desired norm on each
cell $K$ of the triangulation and returns a vector which holds these
values for each cell. From the local values, we can then obtain the global error. For
example, if the vector $\mathbf e$ with element $e_K$ for all cells
$K$ contains the local $L_2$ norms $\|u-u_h\|_K$, then
@f[
  E = \| {\mathbf e} \| = \left( \sum_K e_K^2 \right)^{1/2}
@f]
is the global $L_2$ error $E=\|u-u_h\|_\Omega$.

In the program, we will show how to evaluate and use these quantities, and we
will monitor their values under mesh refinement. Of course, we have to choose
the problem at hand such that we can explicitly state the solution and its
derivatives, but since we want to evaluate the correctness of the program,
this is only reasonable. If we know that the program produces the correct
solution for one (or, if one wants to be really sure: many) specifically
chosen right hand sides, we can be rather confident that it will also compute
the correct solution for problems where we don't know the exact values.

In addition to simply computing these quantities, we will show how to generate
nicely formatted tables from the data generated by this program that
automatically computes convergence rates etc. In addition, we will compare
different strategies for mesh refinement.


<h3>Non-homogeneous Neumann boundary conditions</h3>

The second, totally
unrelated, subject of this example program is the use of non-homogeneous
boundary conditions. These are included into the variational form using
boundary integrals which we have to evaluate numerically when assembling the
right hand side vector.

Before we go into programming, let's have a brief look at the mathematical
formulation. The equation that we want to solve here is the Helmholtz equation
"with the nice sign":
@f[
  -\Delta u + \alpha u = f,
@f]
on the square $[-1,1]^2$ with $\alpha=1$, augmented by Dirichlet boundary conditions
@f[
  u = g_1
@f]
on some part $\Gamma_1$ of the boundary $\Gamma$, and Neumann conditions
@f[
  {\mathbf n}\cdot \nabla u = g_2
@f]
on the rest $\Gamma_2 = \Gamma \backslash \Gamma_1$.
In our particular testcase, we will use $\Gamma_1=\Gamma \cap\{\{x=1\}
\cup \{y=1\}\}$.
(We say that this equation has the "nice sign" because the operator
$-\Delta + \alpha I$ with the identity $I$ and $\alpha>0$ is a positive definite
operator; the <a
href="https://en.wikipedia.org/wiki/Helmholtz_equation">equation with
the "bad sign"</a> is $-\Delta u - \alpha u$ and results from modeling
time-harmonic processes. The operator is not positive
definite if $\alpha>0$ is large, and this leads to all sorts of issues
we need not discuss here. The operator may also not be invertible --
i.e., the equation does not have a unique solution -- if $\alpha$
happens to be one of the eigenvalues of $-\Delta$.)

Because we want to verify the convergence of our numerical solution $u_h$,
we want a setup so that we know the exact solution $u$. This is where
the Method of Manufactured Solutions comes in. To this end, let us
choose a function
@f[
  \bar u(x) = \sum_{i=1}^3 \exp\left(-\frac{|x-x_i|^2}{\sigma^2}\right)
@f]
where the centers $x_i$ of the exponentials are
  $x_1=(-\frac 12,\frac 12)$,
  $x_2=(-\frac 12,-\frac 12)$, and
  $x_3=(\frac 12,-\frac 12)$,
and the half width is set to $\sigma=\frac {1}{8}$. The method of manufactured
solution then says: choose
@f{align*}
  f &= -\Delta \bar u + \bar u, \\
  g_1 &= \bar u|_{\Gamma_1}, \\
  g_2 &= {\mathbf n}\cdot \nabla\bar u|_{\Gamma_2}.
@f}
With this particular choice, we infer that of course the solution of the
original problem happens to be $u=\bar u$. In other words, by choosing
the right hand sides of the equation and the boundary conditions in a
particular way, we have manufactured ourselves a problem to which we
know the solution. This allows us then to compute the error of our
numerical solution. In the code below, we represent $\bar u$ by the
<code>Solution</code> class, and other classes will be used to
denote $\bar u|_{\Gamma_1}=g_1$ and ${\mathbf n}\cdot \nabla\bar u|_{\Gamma_2}=g_2$.

Using the above definitions, we can state the weak formulation of the
equation, which reads: find $u\in H^1_g=\{v\in H^1: v|_{\Gamma_1}=g_1\}$ such
that
@f[
  {(\nabla v, \nabla u)}_\Omega + {(v,u)}_\Omega
  =
  {(v,f)}_\Omega + {(v,g_2)}_{\Gamma_2}
@f]
for all test functions $v\in H^1_0=\{v\in H^1: v|_{\Gamma_1}=0\}$. The
boundary term ${(v,g_2)}_{\Gamma_2}$ has appeared by integration by parts and
using $\partial_n u=g_2$ on $\Gamma_2$ and $v=0$ on $\Gamma_1$. The cell
matrices and vectors which we use to build the global matrices and right hand
side vectors in the discrete formulation therefore look like this:
@f{eqnarray*}
  A_{ij}^K &=& \left(\nabla \varphi_i, \nabla \varphi_j\right)_K
              +\left(\varphi_i, \varphi_j\right)_K,
  \\
  F_i^K &=& \left(\varphi_i, f\right)_K
           +\left(\varphi_i, g_2\right)_{\partial K\cap \Gamma_2}.
@f}
Since the generation of the domain integrals has been shown in previous
examples several times, only the generation of the contour integral is of
interest here. It basically works along the following lines: for domain
integrals we have the <code>FEValues</code> class that provides values and
gradients of the shape values, as well as Jacobian determinants and other
information and specified quadrature points in the cell; likewise, there is a
class <code>FEFaceValues</code> that performs these tasks for integrations on
faces of cells. One provides it with a quadrature formula for a manifold with
dimension one less than the dimension of the domain is, and the cell and the
number of its face on which we want to perform the integration. The class will
then compute the values, gradients, normal vectors, weights, etc. at the
quadrature points on this face, which we can then use in the same way as for
the domain integrals. The details of how this is done are shown in the
following program.


<h3>A note on good programming practice</h3>

Besides the mathematical topics outlined above, we also want to use this
program to illustrate one aspect of good programming practice, namely the use
of namespaces. In programming the deal.II library, we have take great care not
to use names for classes and global functions that are overly generic, say
<code>f(), sz(), rhs()</code> etc. Furthermore, we have put everything into
namespace <code>dealii</code>. But when one writes application programs that
aren't meant for others to use, one doesn't always pay this much attention. If
you follow the programming style of step-1 through step-6, these functions
then end up in the global namespace where, unfortunately, a lot of other stuff
also lives (basically everything the C language provides, along with
everything you get from the operating system through header files). To make
things a bit worse, the designers of the C language were also not always
careful in avoiding generic names; for example, the symbols <code>j1,
jn</code> are defined in C header files (they denote Bessel functions).

To avoid the problems that result if names of different functions or variables
collide (often with confusing error messages), it is good practice to put
everything you do into a <a
href="http://en.wikipedia.org/wiki/Namespace_(computer_science)">namespace</a>. Following
this style, we will open a namespace <code>Step7</code> at the top of the
program, import the deal.II namespace into it, put everything that's specific
to this program (with the exception of <code>main()</code>, which must be in
the global namespace) into it, and only close it at the bottom of the file. In
other words, the structure of the program is of the kind
@code
  #includes ...

  namespace Step7
  {
    using namespace dealii;

    ...everything to do with the program...
  }

  int main ()
  {
    ...do whatever main() does...
  }
@endcode
We will follow this scheme throughout the remainder of the deal.II tutorial.
