<br>

<i>This program was contributed by Bruno Turcksin and Damien Lebrun-Grandie.</i>

@note In order to run this program, deal.II must be configured to use
the UMFPACK sparse direct solver. Refer to the <a
href="../../readme.html#umfpack">ReadMe</a> for instructions how to do this.

<a name="step-52-Intro"></a>
<h1>Introduction</h1>

This program shows how to use Runge-Kutta methods to solve a time-dependent
problem. It solves a small variation of the heat equation discussed first in
step-26 but, since the purpose of this program is only to demonstrate using
more advanced ways to interface with deal.II's time stepping algorithms, only
solves a simple problem on a uniformly refined mesh.

@note At the end of the day, time stepping is a problem that is only
  solved efficiently if you use adaptive time step selection and error
  control.  This is implemented in many external libraries, but not in
  deal.II itself.  You may want to consider looking at step-86 for a
  worked out example. In the meantime, this program is deprecated and
  will be removed after the deal.II 9.6 release.

<h3>Problem statement</h3>

In this example, we solve the one-group time-dependent diffusion
approximation of the neutron transport equation (see step-28 for the
time-independent multigroup diffusion). This is a model for how neutrons move
around highly scattering media, and consequently it is a variant of the
time-dependent diffusion equation -- which is just a different name for the
heat equation discussed in step-26, plus some extra terms.
We assume that the medium is not
fissible and therefore, the neutron flux satisfies the following equation:
@f{eqnarray*}{
\frac{1}{v}\frac{\partial \phi(x,t)}{\partial t} = \nabla \cdot D(x) \nabla \phi(x,t)
- \Sigma_a(x) \phi(x,t) + S(x,t)
@f}
augmented by appropriate boundary conditions. Here, $v$ is the velocity of
neutrons (for simplicity we assume it is equal to 1 which can be achieved by
simply scaling the time variable), $D$ is the diffusion coefficient,
$\Sigma_a$ is the absorption cross section, and $S$ is a source. Because we are
only interested in the time dependence, we assume that $D$ and $\Sigma_a$ are
constant.

Since this program only intends to demonstrate how to use advanced time
stepping algorithms, we will only look for the solutions of relatively simple
problems. Specifically, we are looking for a solution on a square domain
$[0,b]\times[0,b]$ of the form
@f{eqnarray*}{
\phi(x,t) = A\sin(\omega t)(bx-x^2).
@f}
By using quadratic finite elements, we can represent this function exactly at
any particular time, and all the error will be due to the time
discretization. We do this because it is then easy to observe the order of
convergence of the various time stepping schemes we will consider, without
having to separate spatial and temporal errors.

We impose the following boundary conditions: homogeneous Dirichlet for $x=0$ and
$x=b$ and homogeneous Neumann conditions for $y=0$ and $y=b$. We choose the
source term so that the corresponding solution is
in fact of the form stated above:
@f{eqnarray*}{
S=A\left(\frac{1}{v}\omega \cos(\omega t)(bx -x^2) + \sin(\omega t)
\left(\Sigma_a (bx-x^2)+2D\right) \right).
@f}
Because the solution is a sine in time, we know that the exact solution
satisfies $\phi\left(x,\frac{\pi}{\omega}\right) = 0$.
Therefore, the error at time $t=\frac{\pi}{\omega}$ is simply the norm of the numerical
solution, i.e., $\|e(\cdot,t=\frac{\pi}{\omega})\|_{L_2} = \|\phi_h(\cdot,t=\frac{\pi}{\omega})\|_{L_2}$,
and is particularly easily evaluated. In the code, we evaluate the $l_2$ norm
of the vector of nodal values of $\phi_h$ instead of the $L_2$ norm of the
associated spatial function, since the former is simpler to compute; however,
on uniform meshes, the two are just related by a constant and we can
consequently observe the temporal convergence order with either.


<h3>Runge-Kutta methods</h3>

The Runge-Kutta methods implemented in deal.II assume that the equation to be
solved can be written as:
@f{eqnarray*}{
\frac{dy}{dt} = g(t,y).
@f}
On the other hand, when using finite elements, discretized time derivatives always result in the
presence of a @ref GlossMassMatrix "mass matrix" on the left hand side. This can easily be seen by
considering that if the solution vector $y(t)$ in the equation above is in fact the vector
of nodal coefficients $U(t)$ for a variable of the form
@f{eqnarray*}{
  u_h(x,t) = \sum_j U_j(t) \varphi_j(x)
@f}
with spatial shape functions $\varphi_j(x)$, then multiplying an equation of
the form
@f{eqnarray*}{
  \frac{\partial u(x,t)}{\partial t} = q(t,u(x,t))
@f}
by test functions, integrating over $\Omega$, substituting $u\rightarrow u_h$
and restricting the test functions to the $\varphi_i(x)$ from above, then this
spatially discretized equation has the form
@f{eqnarray*}{
M\frac{dU}{dt} = f(t,U),
@f}
where $M$ is the mass matrix and $f(t,U)$ is the spatially discretized version
of $q(t,u(x,t))$ (where $q$ is typically the place where spatial
derivatives appear, but this is not of much concern for the moment given that
we only consider time derivatives). In other words, this form fits the general
scheme above if we write
@f{eqnarray*}{
\frac{dy}{dt} = g(t,y) = M^{-1}f(t,y).
@f}

Runke-Kutta methods are time stepping schemes that approximate $y(t_n)\approx
y_{n}$ through a particular one-step approach. They are typically written in the form
@f{eqnarray*}{
y_{n+1} = y_n + \sum_{i=1}^s b_i k_i
@f}
where for the form of the right hand side above
@f{eqnarray*}{
k_i = \Delta t \, M^{-1} f\left(t_n+c_ih,y_n+\sum_{j=1}^sa_{ij}k_j\right).
@f}
Here $a_{ij}$, $b_i$, and $c_i$ are known coefficients that identify which
particular Runge-Kutta scheme you want to use, and $\Delta t=t_{n+1}-t_n$ is the time step
used. Different time stepping methods of the Runge-Kutta class differ in the
number of stages $s$ and the values they use for the coefficients $a_{ij}$,
$b_i$, and $c_i$ but are otherwise easy to implement since one can look up
tabulated values for these coefficients. (These tables are often called
Butcher tableaus.)

At the time of the writing of this tutorial, the methods implemented in
deal.II can be divided in three categories:
<ol>
<li> Explicit Runge-Kutta; in order for a method to be explicit, it is
necessary that in the formula above defining $k_i$, $k_i$ does not appear
on the right hand side. In other words, these methods have to satisfy
$a_{ii}=0, i=1,\ldots,s$.
<li> Embedded (or adaptive) Runge-Kutta; we will discuss their properties below.
<li> Implicit Runge-Kutta; this class of methods require the solution of a
possibly nonlinear system the stages $k_i$ above, i.e., they have
$a_{ii}\neq 0$ for at least one of the stages $i=1,\ldots,s$.
</ol>
Many well known time stepping schemes that one does not typically associate
with the names Runge or Kutta can in fact be written in a way so that they,
too, can be expressed in these categories. They oftentimes represent the
lowest-order members of these families; one example is the simple explicit
Euler method.


<h4>Explicit Runge-Kutta methods</h4>

These methods, only require a function to evaluate $M^{-1}f(t,y)$ but not
(as implicit methods) to solve an equation that involves
$f(t,y)$ for $y$. As all explicit time stepping methods, they become unstable
when the time step chosen is too large.

Well known methods in this class include forward Euler, third order
Runge-Kutta, and fourth order Runge-Kutta (often abbreviated as RK4).


<h4>Embedded Runge-Kutta methods</h4>

These methods use both a lower and a higher order method to
estimate the error and decide if the time step needs to be shortened or can be
increased. The term "embedded" refers to the fact that the lower-order method
does not require additional evaluates of the function $M^{-1}f(\cdot,\cdot)$
but reuses data that has to be computed for the high order method anyway. It
is, in other words, essentially free, and we get the error estimate as a side
product of using the higher order method.

This class of methods include Heun-Euler, Bogacki-Shampine, Dormand-Prince (ode45 in
Matlab and often abbreviated as RK45 to indicate that the lower and higher order methods
used here are 4th and 5th order Runge-Kutta methods, respectively), Fehlberg,
and Cash-Karp.

At the time of the writing, only embedded explicit methods have been implemented.


<h4>Implicit Runge-Kutta methods</h4>

Implicit methods require the solution of (possibly nonlinear) systems of the
form $\alpha y = f(t,y)$
for $y$ in each (sub-)timestep. Internally, this is
done using a Newton-type method and, consequently, they require that the user
provide functions that can evaluate $M^{-1}f(t,y)$ and
$\left(I-\tau M^{-1} \frac{\partial f}{\partial y}\right)^{-1}$ or equivalently
$\left(M - \tau \frac{\partial f}{\partial y}\right)^{-1} M$.

The particular form of this operator results from the fact that each Newton
step requires the solution of an equation of the form
@f{align*}{
  \left(M - \tau \frac{\partial f}{\partial y}\right) \Delta y
  = -M h(t,y)
@f}
for some (given) $h(t,y)$. Implicit methods are
always stable, regardless of the time step size, but too large time steps of
course affect the <i>accuracy</i> of the solution, even if the numerical
solution remains stable and bounded.

Methods in this class include backward Euler, implicit midpoint,
Crank-Nicolson, and the two stage SDIRK method (short for "singly diagonally
implicit Runge-Kutta", a term coined to indicate that the diagonal elements
$a_{ii}$ defining the time stepping method are all equal; this property
allows for the Newton matrix $I-\tau M^{-1}\frac{\partial f}{\partial y}$ to
be re-used between stages because $\tau$ is the same every time).


<h3>Spatially discrete formulation</h3>

By expanding the solution of our model problem
as always using shape functions $\psi_j$ and writing
@f{eqnarray*}{
\phi_h(x,t) = \sum_j U_j(t) \psi_j(x),
@f}
we immediately get the spatially discretized version of the diffusion equation as
@f{eqnarray*}{
  M \frac{dU(t)}{dt}
  = -{\cal D} U(t) - {\cal A} U(t) + {\cal S}(t)
@f}
where
@f{eqnarray*}{
  M_{ij}  &=& (\psi_i,\psi_j), \\
  {\cal D}_{ij}  &=& (D\nabla\psi_i,\nabla\psi_j)_\Omega, \\
  {\cal A}_{ij}  &=& (\Sigma_a\psi_i,\psi_j)_\Omega, \\
  {\cal S}_{i}(t)  &=& (\psi_i,S(x,t))_\Omega.
@f}
See also step-24 and step-26 to understand how we arrive here.
Boundary terms are not necessary due to the chosen boundary conditions for
the current problem. To use the Runge-Kutta methods, we recast this
as follows:
@f{eqnarray*}{
f(y) = -{\cal D}y - {\cal A}y + {\cal S}.
@f}
In the code, we will need to be able to evaluate this function $f(U)$ along
with its derivative,
@f{eqnarray*}{
\frac{\partial f}{\partial y} = -{\cal D} - {\cal A}.
@f}


<h3>Notes on the testcase</h3>

To simplify the problem, the domain is two dimensional and the mesh is
uniformly refined (there is no need to adapt the mesh since we use quadratic
finite elements and the exact solution is quadratic). Going from a two
dimensional domain to a three dimensional domain is not very
challenging. However if you intend to solve more complex problems where the
mesh must be adapted (as is done, for example, in step-26), then it is
important to remember the following issues:

<ol>
<li> You will need to project the solution to the new mesh when the mesh is changed. Of course,
     the mesh
     used should be the same from the beginning to the end of each time step,
     a question that arises because Runge-Kutta methods use multiple
     evaluations of the equations within each time step.
<li> You will need to update the mass matrix and its inverse every time the
     mesh is changed.
</ol>
The techniques for these steps are readily available by looking at step-26.
