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

This program grew out of a student project by Yan Li at Texas A&amp;M
University. Most of the work for this program is by her.

In this project, we propose a numerical simulation for two phase
flow problems in porous media. This problem includes one
elliptic equation and one nonlinear, time dependent transport
equation. This is therefore also the first time-dependent tutorial
program (besides the somewhat strange time-dependence of @ref step_18
"step-18").

The equations covered here are an extension of the material already covered in
step-20. In particular, they fall into the class of
vector-valued problems. A toplevel overview of this topic can be found in the
@ref vector_valued module.


<h3>The two phase flow problem</h3>

Modeling of two phase flow in porous media is important for both
environmental remediation and the management of petroleum and groundwater
reservoirs. Practical situations involving two phase flow include the
dispersal of a nonaqueous phase liquid in an aquifer, or the joint
movement of a mixture of fluids such as oil and water in a
reservoir. Simulation models, if they are to provide realistic
predictions, must accurately account for these effects.

To derive the governing equations, consider two phase flow in a
reservoir $\Omega$ under the assumption that the movement of fluids is
dominated by viscous effects; i.e. we neglect the effects of gravity,
compressibility, and capillary pressure. Porosity will be considered
to be constant. We will denote variables referring to either of the two
phases using subscripts $w$ and $o$, short for water and oil. The
derivation of the equations holds for other pairs of fluids as well,
however.

The velocity with which molecules of each of the two phases move is
determined by Darcy's law that states that the velocity is
proportional to the pressure gradient:
@f{eqnarray*}
  \mathbf{u}_{j}
  =
  -\frac{k_{rj}(S)}{\mu_{j}} \mathbf{K} \cdot \nabla p
@f}
where $\mathbf{u}_{j}$ is the velocity of phase $j=o,w$, $K$ is the
permeability tensor, $k_{rj}$ is the relative permeability of phase
$j$, $p$ is the
pressure and $\mu_{j}$ is the viscosity of phase $j$. Finally, $S$ is
the saturation (volume fraction), i.e. a function with values between
0 and 1 indicating the composition of the mixture of fluids. In
general, the coefficients $K, k_{rj}, \mu$ may be spatially dependent
variables, and we will always treat them as non-constant functions in
the following.

We combine Darcy's law with the statement of conservation of mass for
each phase,
@f[
  \textrm{div}\ \mathbf{u}_{j} = q_j,
@f]
with a source term for each phase. By summing over the two phases,
we can express the governing equations in terms of the
so-called pressure equation:
@f{eqnarray*}
- \nabla \cdot (\mathbf{K}\lambda(S) \nabla p)= q.
@f}
Here, $q$ is the sum source term, and
@f[
  \lambda(S) = \frac{k_{rw}(S)}{\mu_{w}}+\frac{k_{ro}(S)}{\mu_{o}}
@f]
is the total mobility.

So far, this looks like an ordinary stationary, Poisson-like equation that we
can solve right away with the techniques of the first few tutorial programs
(take a look at step-6, for example, for something very
similar). However, we have not said anything yet about the saturation, which
of course is going to change as the fluids move around.

The second part of the equations is the description of the
dynamics of the saturation, i.e., how the relative concentration of the
two fluids changes with time. The saturation equation for the displacing
fluid (water) is given by the following conservation law:
@f{eqnarray*}
  S_{t} + \nabla \cdot (F(S) \mathbf{u}) = q_{w},
@f}
which can be rewritten by using the product rule of the divergence operator
in the previous equation:
@f{eqnarray*}
  S_{t} + F(S) \left[\nabla \cdot \mathbf{u}\right]
        + \mathbf{u} \cdot \left[ \nabla F(S)\right]
  = S_{t} + F(S) q + \mathbf{u} \cdot \nabla F(S) = q_{w}.
@f}
Here, $q=\nabla\cdot \mathbf{u}$ is the total influx introduced
above, and $q_{w}$ is the flow rate of the displacing fluid (water).
These two are related to the fractional flow $F(S)$ in the following way:
@f[
  q_{w} = F(S) q,
@f]
where the fractional flow is often parameterized via the (heuristic) expression
@f[
  F(S)
  =
  \frac{k_{rw}(S)/\mu_{w}}{k_{rw}(S)/\mu_{w} + k_{ro}(S)/\mu_{o}}.
@f]
Putting it all together yields the saturation equation in the following,
advected form:
@f{eqnarray*}
  S_{t} + \mathbf{u} \cdot \nabla F(S) = 0,
@f}
where $\mathbf u$ is the total velocity
@f[
  \mathbf{u} =
  \mathbf{u}_{o} + \mathbf{u}_{w} = -\lambda(S) \mathbf{K}\cdot\nabla p.
@f]
Note that the advection equation contains the term $\mathbf{u} \cdot \nabla
F(S)$ rather than $\mathbf{u} \cdot \nabla S$ to indicate that the saturation
is not simply transported along; rather, since the two phases move with
different velocities, the saturation can actually change even in the advected
coordinate system. To see this, rewrite $\mathbf{u} \cdot \nabla F(S)
= \mathbf{u} F'(S) \cdot \nabla S$ to observe that the <i>actual</i>
velocity with which the phase with saturation $S$ is transported is
$\mathbf u F'(S)$ whereas the other phase is transported at velocity
$\mathbf u (1-F'(S))$. $F(S)$ is consequently often referred to as the
<i>fractional flow</i>.

In summary, what we get are the following two equations:
@f{eqnarray*}
  - \nabla \cdot (\mathbf{K}\lambda(S) \nabla p) &=& q
  \qquad \textrm{in}\ \Omega\times[0,T],
  \\
  S_{t} + \mathbf{u} \cdot \nabla F(S) &=& 0
  \qquad \textrm{in}\ \Omega\times[0,T].
@f}
Here, $p=p(\mathbf x, t), S=S(\mathbf x, t)$ are now time dependent
functions: while at every time instant the flow field is in
equilibrium with the pressure (i.e. we neglect dynamic
accelerations), the saturation is transported along with the flow and
therefore changes over time, in turn affected the flow field again
through the dependence of the first equation on $S$.

This set of equations has a peculiar character: one of the two
equations has a time derivative, the other one doesn't. This
corresponds to the character that the pressure and velocities are
coupled through an instantaneous constraint, whereas the saturation
evolves over finite time scales.

Such systems of equations are called Differential Algebraic Equations
(DAEs), since one of the equations is a differential equation, the
other is not (at least not with respect to the time variable) and is
therefore an "algebraic" equation. (The notation comes from the field
of ordinary differential equations, where everything that does not
have derivatives with respect to the time variable is necessarily an
algebraic equation.) This class of equations contains pretty
well-known cases: for example, the time dependent Stokes and
Navier-Stokes equations (where the algebraic constraint is that the
divergence of the flow field, $\textrm{div}\ \mathbf u$, must be zero)
as well as the time dependent Maxwell equations (here, the algebraic
constraint is that the divergence of the electric displacement field
equals the charge density, $\textrm{div}\ \mathbf D = \rho$ and that the
divergence of the magnetic flux density is zero: $\textrm{div}\ \mathbf
B = 0$); even the quasistatic model of step-18 falls into this
category. We will see that the different character of the two equations
will inform our discretization strategy for the two equations.


<h3>Time discretization</h3>

In the reservoir simulation community, it is common to solve the equations
derived above by going back to the first order, mixed formulation. To this
end, we re-introduce the total velocity $\mathbf u$ and write the equations in
the following form:
@f{eqnarray*}
  \mathbf{u}+\mathbf{K}\lambda(S) \nabla p&=&0 \\
  \nabla \cdot\mathbf{u} &=& q \\
  S_{t} + \mathbf{u} \cdot \nabla F(S) &=& 0.
@f}
This formulation has the additional benefit that we do not have to express the
total velocity $\mathbf u$ appearing in the transport equation as a function
of the pressure, but can rather take the primary variable for it. Given the
saddle point structure of the first two equations and their similarity to the
mixed Laplace formulation we have introduced in step-20, it
will come as no surprise that we will use a mixed discretization again.

But let's postpone this for a moment. The first business we have with these
equations is to think about the time discretization. In reservoir simulation,
there is a rather standard algorithm that we will use here. It first solves
the pressure using an implicit equation, then the saturation using an explicit
time stepping scheme. The algorithm is called IMPES for IMplicit Pressure
Explicit Saturation and was first proposed a long time ago: by Sheldon et
al. in 1959 and Stone and Gardner in 1961 (J. W. Sheldon, B. Zondek and
W. T. Cardwell: <i>One-dimensional, incompressible, non-capillary, two-phase
fluid flow in a porous medium</i>, Trans. SPE AIME, 216 (1959), pp. 290-296; H.
L. Stone and A. O. Gardner Jr: <i>Analysis of gas-cap or dissolved-gas
reservoirs</i>, Trans. SPE AIME, 222 (1961), pp. 92-104).
In a slightly modified form, this algorithm can be
written as follows: for each time step, solve
@f{eqnarray*}
  \mathbf{u}^{n+1}+\mathbf{K}\lambda(S^n) \nabla p^{n+1}&=&0 \\
  \nabla \cdot\mathbf{u}^{n+1} &=& q^{n+1} \\
  \frac {S^{n+1}-S^n}{\triangle t} + \mathbf{u}^{n+1} \cdot \nabla F(S^n) &=& 0,
@f}
where $\triangle t$ is the length of a time step. Note how we solve the
implicit pressure-velocity system that only depends on the previously computed
saturation $S^n$, and then do an explicit time step for $S^{n+1}$ that only
depends on the previously known $S^n$ and the just computed
$\mathbf{u}^{n+1}$. This way, we never have to iterate for the nonlinearities
of the system as we would have if we used a fully implicit method. (In
a more modern perspective, this should be seen as an "operator
splitting" method. step-58 has a long description of the idea behind this.)

We can then state the problem in weak form as follows, by multiplying each
equation with test functions $\mathbf v$, $\phi$, and $\sigma$ and integrating
terms by parts:
@f{eqnarray*}
  \left((\mathbf{K}\lambda(S^n))^{-1} \mathbf{u}^{n+1},\mathbf v\right)_\Omega -
  (p^{n+1}, \nabla\cdot\mathbf v)_\Omega &=&
  - (p^{n+1}, \mathbf v)_{\partial\Omega}
  \\
  (\nabla \cdot\mathbf{u}^{n+1}, \phi)_\Omega &=& (q^{n+1},\phi)_\Omega
@f}
Note that in the first term, we have to prescribe the pressure $p^{n+1}$ on
the boundary $\partial\Omega$ as boundary values for our problem. $\mathbf n$
denotes the unit outward normal vector to $\partial K$, as usual.

For the saturation equation, we obtain after integrating by parts
@f{eqnarray*}
  (S^{n+1}, \sigma)_\Omega
  -
  \triangle t
  \sum_K
  \left\{
  \left(F(S^n), \nabla \cdot (\mathbf{u}^{n+1} \sigma)\right)_K
  -
  \left(F(S^n) (\mathbf n \cdot \mathbf{u}^{n+1}, \sigma\right)_{\partial K}
  \right\}
  &=&
  (S^n,\sigma)_\Omega.
@f}
Using the fact that $\nabla \cdot \mathbf{u}^{n+1}=q^{n+1}$, we can rewrite the
cell term to get an equation as follows:
@f{eqnarray*}
  (S^{n+1}, \sigma)_\Omega
  -
  \triangle t
  \sum_K
  \left\{
  \left(F(S^n) \mathbf{u}^{n+1}, \nabla \sigma\right)_K
  -
  \left(F(S^n) (\mathbf n \cdot \mathbf{u}^{n+1}), \sigma\right)_{\partial K}
  \right\}
  &=&
  (S^n,\sigma)_\Omega +
  \triangle t \sum_K  \left(F(S^n) q^{n+1}, \sigma\right)_K.
@f}
We introduce an object of type DiscreteTime in order to keep track of the
current value of time and time step in the code. This class encapsulates many
complexities regarding adjusting time step size and stopping at a specified
final time.



<h3>Space discretization</h3>

In each time step, we then apply the mixed finite method of @ref step_20
"step-20" to the velocity and pressure. To be well-posed, we choose
Raviart-Thomas spaces $RT_{k}$ for $\mathbf{u}$ and discontinuous elements of
class $DGQ_{k}$ for $p$. For the saturation, we will also choose $DGQ_{k}$
spaces.

Since we have discontinuous spaces, we have to think about how to evaluate
terms on the interfaces between cells, since discontinuous functions are not
really defined there. In particular, we have to give a meaning to the last
term on the left hand side of the saturation equation. To this end, let us
define that we want to evaluate it in the following sense:
@f{eqnarray*}
  &&\left(F(S^n) (\mathbf n \cdot \mathbf{u}^{n+1}), \sigma\right)_{\partial K}
  \\
  &&\qquad =
  \left(F(S^n_+) (\mathbf n \cdot \mathbf{u}^{n+1}_+), \sigma\right)_{\partial K_+}
  +
  \left(F(S^n_-) (\mathbf n \cdot \mathbf{u}^{n+1}_-), \sigma\right)_{\partial K_-},
@f}
where $\partial K_{-} \dealcoloneq \{x\in \partial K, \mathbf{u}(x) \cdot \mathbf{n}<0\}$
denotes the inflow boundary and $\partial K_{+} \dealcoloneq \{\partial K \setminus
\partial K_{-}\}$ is the outflow part of the boundary.
The quantities $S_+,\mathbf{u}_+$ then correspond to the values of these
variables on the present cell, whereas $S_-,\mathbf{u}_-$ (needed on the
inflow part of the boundary of $K$) are quantities taken from the neighboring
cell. Some more context on discontinuous element techniques and evaluation of
fluxes can also be found in step-12 and step-12b.


<h3>Linear solvers</h3>

The linear solvers used in this program are a straightforward extension of the
ones used in step-20 (but without LinearOperator). Essentially, we simply have
to extend everything from
two to three solution components. If we use the discrete spaces
mentioned above and put shape functions into the bilinear forms, we
arrive at the following linear system to be solved for time step $n+1$:
@f[
\left(
\begin{array}{ccc}
M^u(S^{n}) & B^{T}& 0\\
B &    0 & 0\\
\triangle t\; H &    0& M^S
\end{array}
\right)
\left(
\begin{array}{c}
\mathbf{U}^{n+1} \\ P^{n+1} \\ S^{n+1}
\end{array}
\right)
=
\left(
\begin{array}{c}
0 \\ F_2 \\ F_3
\end{array}
\right)
@f]
where the individual matrices and vectors are defined as follows using
shape functions $\mathbf v_i$ (of type Raviart Thomas $RT_k$) for
velocities and $\phi_i$ (of type $DGQ_k$) for both pressures and saturations:
@f{eqnarray*}
M^u(S^n)_{ij} &=&
\left((\mathbf{K}\lambda(S^n))^{-1} \mathbf{v}_i,\mathbf
v_j\right)_\Omega,
\\
B_{ij} &=&
-(\nabla \cdot \mathbf v_j, \phi_i)_\Omega,
\\
H_{ij} &=&
  -
  \sum_K
  \left\{
  \left(F(S^n) \mathbf v_i, \nabla \phi_j)\right)_K
  -
  \left(F(S^n_+) (\mathbf n \cdot (\mathbf v_i)_+), \phi_j\right)_{\partial K_+}
  -
  \left(F(S^n_-) (\mathbf n \cdot (\mathbf v_i)_-), \phi_j\right)_{\partial K_-},
  \right\}
\\
M^S_{ij} &=&
(\phi_i, \phi_j)_\Omega,
\\
(F_2)_i &=&
-(q^{n+1},\phi_i)_\Omega,
\\
(F_3)_i &=&
(S^n,\phi_i)_\Omega +\triangle t \sum_K  \left(F(S^n) q^{n+1}, \phi_i\right)_K.
@f}

@note Due to historical accidents, the role of matrices $B$ and $B^T$
has been reverted in this program compared to step-20. In other words,
here $B$ refers to the divergence and $B^T$ to the gradient operators
when it was the other way around in step-20.

The system above presents a complication: Since the matrix $H_{ij}$
depends on $\mathbf u^{n+1}$ implicitly (the velocities are needed to
determine which parts of the boundaries $\partial K$ of cells are
influx or outflux parts), we can only assemble this matrix after we
have solved for the velocities.

The solution scheme then involves the following steps:
<ol>
  <li>Solve for the pressure $p^{n+1}$ using the Schur complement
  technique introduced in step-20.

  <li>Solve for the velocity $\mathbf u^{n+1}$ as also discussed in
  step-20.

  <li>Compute the term $F_3-\triangle t\; H \mathbf u^{n+1}$, using
  the just computed velocities.

  <li>Solve for the saturation $S^{n+1}$.
</ol>

In this scheme, we never actually build the matrix $H$, but rather
generate the right hand side of the third equation once we are ready
to do so.

In the program, we use a variable <code>solution</code> to store the
solution of the present time step. At the end of each step, we copy
its content, i.e. all three of its block components, into the variable
<code>old_solution</code> for use in the next time step.


<h3>Choosing a time step</h3>

A general rule of thumb in hyperbolic transport equations like the equation we
have to solve for the saturation equation is that if we use an explicit time
stepping scheme, then we should use a time step such that the distance that a
particle can travel within one time step is no larger than the diameter of a
single cell. In other words, here, we should choose
@f[
  \triangle t_{n+1} \le \frac h{|\mathbf{u}^{n+1}(\mathbf{x})|}.
@f]
Fortunately, we are in a position where we can do that: we only need the
time step when we want to assemble the right hand side of the saturation
equation, which is after we have already solved for $\mathbf{u}^{n+1}$. All we
therefore have to do after solving for the velocity is to loop over all
quadrature points in the domain and determine the maximal magnitude of the
velocity. We can then set the time step for the saturation equation to
@f[
  \triangle t_{n+1} = \frac {\min_K h_K}{\max_{\mathbf{x}}|\mathbf{u}^{n+1}(\mathbf{x})|}.
@f]

Why is it important to do this? If we don't, then we will end up with lots of
places where our saturation is larger than one or less than zero, as can
easily be verified. (Remember that the saturation corresponds to something
like the water fraction in the fluid mixture, and therefore must physically be
between 0 and 1.) On the other hand, if we choose our time step according to
the criterion listed above, this only happens very very infrequently &mdash;
in fact only once for the entire run of the program. However, to be on the
safe side, however, we run a function <code>project_back_saturation</code> at
the end of each time step, that simply projects the saturation back onto the
interval $[0,1]$, should it have gotten out of the physical range. This is
useful since the functions $\lambda(S)$ and $F(S)$ do not represent anything
physical outside this range, and we should not expect the program to do
anything useful once we have negative saturations or ones larger than one.

Note that we will have similar restrictions on the time step also in
step-23 and step-24 where we solve the time dependent
wave equation, another hyperbolic problem. We will also come back to the issue
of time step choice below in the section on <a href="#extensions">possible
extensions to this program</a>.


<h3>The test case</h3>

For simplicity, this program assumes that there is no source, $q=0$, and that
the heterogeneous porous medium is isotropic $\mathbf{K}(\mathbf{x}) =
k(\mathbf{x}) \mathbf{I}$. The first one of these is a realistic assumption in
oil reservoirs: apart from injection and production wells, there are usually
no mechanisms for fluids to appear or disappear out of the blue. The second
one is harder to justify: on a microscopic level, most rocks are isotropic,
because they consist of a network of interconnected pores. However, this
microscopic scale is out of the range of today's computer simulations, and we
have to be content with simulating things on the scale of meters. On that
scale, however, fluid transport typically happens through a network of cracks
in the rock, rather than through pores. However, cracks often result from
external stress fields in the rock layer (for example from tectonic faulting)
and the cracks are therefore roughly aligned. This leads to a situation where
the permeability is often orders of magnitude larger in the direction parallel
to the cracks than perpendicular to the cracks. A problem typically faces in
reservoir simulation, however, is that the modeler doesn't know the direction
of cracks because oil reservoirs are not accessible to easy inspection. The
only solution in that case is to assume an effective, isotropic permeability.

Whatever the matter, both of these restrictions, no sources and isotropy,
would be easy to lift with a few lines of code in the program.

Next, for simplicity, our numerical simulation will be done on the
unit cell $\Omega = [0,1]\times [0,1]$ for $t\in [0,T]$. Our initial
conditions are $S(\mathbf{x},0)=0$; in the oil reservoir picture, where $S$
would indicate the water saturation, this means that the reservoir contains
pure oil at the beginning. Note that we do not need any initial
conditions for pressure or velocity, since the equations do not contain time
derivatives of these variables. Finally, we impose the following pressure
boundary conditions:
@f[
  p(\mathbf{x},t)=1-x_1 \qquad \textrm{on}\ \partial\Omega.
@f]
Since the pressure and velocity solve a mixed form Poisson equation, the
imposed pressure leads to a resulting flow field for the velocity. On the
other hand, this flow field determines whether a piece of the boundary is of
inflow or outflow type, which is of relevance because we have to impose
boundary conditions for the saturation on the inflow part of the boundary,
@f[
  \Gamma_{in}(t) = \{\mathbf{x}\in\partial\Omega:
                     \mathbf{n} \cdot \mathbf{u}(\mathbf{x},t) < 0\}.
@f]
On this inflow boundary, we impose the following saturation values:
@f{eqnarray}
  S(\mathbf{x},t) = 1 & \textrm{on}\ \Gamma_{in}\cap\{x_1=0\},
  \\
  S(\mathbf{x},t) = 0 & \textrm{on}\ \Gamma_{in}\backslash \{x_1=0\}.
@f}
In other words, we have pure water entering the reservoir at the left, whereas
the other parts of the boundary are in contact with undisturbed parts of the
reservoir and whenever influx occurs on these boundaries, pure oil will enter.

In our simulations, we choose the total mobility as
@f[
  \lambda (S) = \frac{1.0}{\mu} S^2 +(1-S)^2
@f]
where we use $\mu=0.2$ for the viscosity. In addition, the fractional flow of
water is given by
@f[
  F(S)=\frac{S^2}{S^2+\mu (1-S)^2}
@f]

@note Coming back to this testcase in step-43 several years later revealed an
oddity in the setup of this testcase. To this end, consider that we can
rewrite the advection equation for the saturation as $S_{t} + (\mathbf{u}
F'(S)) \cdot \nabla S = 0$. Now, at the initial time, we have $S=0$, and with
the given choice of function $F(S)$, we happen to have $F'(0)=0$. In other
words, at $t=0$, the equation reduces to $S_t=0$ for all $\mathbf x$, so the
saturation is zero everywhere and it is going to stay zero everywhere! This is
despite the fact that $\mathbf u$ is not necessarily zero: the combined fluid
is moving, but we've chosen our partial flux $F(S)$ in such a way that
infinitesimal amounts of wetting fluid also only move at infinitesimal speeds
(i.e., they stick to the medium more than the non-wetting phase in which they
are embedded). That said, how can we square this with the knowledge that
wetting fluid is invading from the left, leading to the flow patterns seen in
the <a href="#Results">results section</a>? That's where we get into
mathematics: Equations like the transport equation we are considering here
have infinitely many solutions, but only one of them is physical: the one that
results from the so-called viscosity limit, called the <a
href="http://en.wikipedia.org/wiki/Viscosity_solution">viscosity
solution</a>. The thing is that with discontinuous elements we arrive at this
viscosity limit because using a numerical flux introduces a finite amount of
artificial viscosity into the numerical scheme. On the other hand, in step-43,
we use an artificial viscosity that is proportional to $\|\mathbf u F'(S)\|$
on every cell, which at the initial time is zero. Thus, the saturation there is
zero and remains zero; the solution we then get is <i>one</i> solution of the
advection equation, but the method does not converge to the viscosity solution
without further changes. We will therefore use a different initial condition in
that program.


Finally, to come back to the description of the testcase, we will show results
for computations with the two permeability
functions introduced at the end of the results section of @ref step_20
"step-20":
<ul>
  <li>A function that models a single, winding crack that snakes through the
  domain. In analogy to step-20, but taking care of the slightly
  different geometry we have here, we describe this by the following function:
  @f[
    k(\mathbf x)
    =
    \max \left\{ e^{-\left(\frac{x_2-\frac 12 - 0.1\sin(10x_1)}{0.1}\right)^2}, 0.01 \right\}.
  @f]
  Taking the maximum is necessary to ensure that the ratio between maximal and
  minimal permeability remains bounded. If we don't do that, permeabilities
  will span many orders of magnitude. On the other hand, the ratio between
  maximal and minimal permeability is a factor in the condition number of the
  Schur complement matrix, and if too large leads to problems for which our
  linear solvers will no longer converge properly.

  <li>A function that models a somewhat random medium. Here, we choose
  @f{eqnarray*}
    k(\mathbf x)
    &=&
    \min \left\{ \max \left\{ \sum_{i=1}^N \sigma_i(\mathbf{x}), 0.01 \right\}, 4\right\},
    \\
    \sigma_i(\mathbf x)
    &=&
    e^{-\left(\frac{|\mathbf{x}-\mathbf{x}_i|}{0.05}\right)^2},
  @f}
  where the centers $\mathbf{x}_i$ are $N$ randomly chosen locations inside
  the domain. This function models a domain in which there are $N$ centers of
  higher permeability (for example where rock has cracked) embedded in a
  matrix of more pristine, unperturbed background rock. Note that here we have
  cut off the permeability function both above and below to ensure a bounded
  condition number.
</ul>
