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

@dealiiVideoLecture{10}

<h3>The basic functioning of finite elements</h3>

This is the first example where we actually use finite elements to compute
something. We
will solve a simple version of Poisson's equation with zero boundary
values, but a nonzero right hand side:
@f{align*}
  -\Delta u &= f \qquad\qquad & \text{in}\ \Omega,
  \\
  u &= 0 \qquad\qquad & \text{on}\ \partial\Omega.
@f}
We will solve this equation on the unit square, $\Omega=[0,1]^2$, for which
you've already learned how to generate a mesh in step-1 and step-2. In
this program, we will also only consider the particular case
$f(\mathbf x)=1$ and come back to how to implement the more general
case in the next tutorial program, step-4.

If you've learned about the basics of the finite element method, you will
remember the steps we need to take to approximate the solution $u$ by a finite
dimensional approximation. Specifically, we first need to derive the weak form
of the equation above, which we obtain by multiplying the equation by a test
function $\varphi$ <i>from the left</i> (we will come back to the reason for
multiplying from the left and not from the right below) and integrating over
the domain $\Omega$:
@f{align*}
  -\int_\Omega \varphi \Delta u = \int_\Omega \varphi f.
@f}
This can be integrated by parts:
@f{align*}
  \int_\Omega \nabla\varphi \cdot \nabla u
  -
  \int_{\partial\Omega} \varphi \mathbf{n}\cdot \nabla u
   = \int_\Omega \varphi f.
@f}
The test function $\varphi$ has to satisfy the same kind of boundary
conditions (in mathematical terms: it needs to come from the tangent space of
the set in which we seek the solution), so on the boundary $\varphi=0$ and
consequently the weak form we are looking for reads
@f{align*}
  (\nabla\varphi, \nabla u)
   = (\varphi, f),
@f}
where we have used the common notation $(a,b)=\int_\Omega a\; b$. The problem
then asks for a function $u$ for which this statement is true for all test
functions $\varphi$ from the appropriate space (which here is the space
$H^1$).

Of course we can't find such a function on a computer in the general case, and
instead we seek an approximation $u_h(\mathbf x)=\sum_j U_j \varphi_j(\mathbf
x)$, where the $U_j$ are unknown expansion coefficients we need to determine
(the "degrees of freedom" of this problem), and $\varphi_i(\mathbf x)$ are the
finite element shape functions we will use. To define these shape functions,
we need the following:

- A mesh on which to define shape functions. You have already seen how to
  generate and manipulate the objects that describe meshes in step-1 and
  step-2.
- A finite element that describes the shape functions we want to use on the
  reference cell (which in deal.II is always the unit interval $[0,1]$, the
  unit square $[0,1]^2$ or the unit cube $[0,1]^3$, depending on which space
  dimension you work in. In step-2, we had already used an object of type
  FE_Q<2>, which denotes the usual Lagrange elements that define shape
  functions by interpolation on support points. The simplest one is
  FE_Q<2>(1), which uses polynomial degree 1. In 2d, these are often referred
  to as <i>bilinear</i>, since they are linear in each of the two coordinates
  of the reference cell. (In 1d, they would be <i>linear</i> and in 3d
  <i>tri-linear</i>; however, in the deal.II documentation, we will frequently
  not make this distinction and simply always call these functions "linear".)
- A DoFHandler object that enumerates all the degrees of freedom on the mesh,
  taking the reference cell description the finite element object provides as
  the basis. You've also already seen how to do this in step-2.
- A mapping that tells how the shape functions on the real cell are obtained
  from the shape functions defined by the finite element class on the
  reference cell. By default, unless you explicitly say otherwise, deal.II
  will use a (bi-, tri-)linear mapping for this, so in most cases you don't
  have to worry about this step.

Through these steps, we now have a set of functions $\varphi_i$, and we can
define the weak form of the discrete problem: Find a function $u_h$, i.e. find
the expansion coefficients $U_i$ mentioned above, so that
@f{align*}
  (\nabla\varphi_i, \nabla u_h)
   = (\varphi_i, f),
   \qquad\qquad
   i=0\ldots N-1.
@f}
Note that we here follow the convention that everything is counted starting at
zero, as common in C and C++. This equation can be rewritten as a linear
system by inserting the representation $u_h(\mathbf x)=\sum_j U_j
\varphi_j(\mathbf x)$: Find a vector $U$ so that
@f{align*}
  A U = F,
@f}
where the matrix $A$ and the right hand side $F$ are defined as
@f{align*}
  A_{ij} &= (\nabla\varphi_i, \nabla \varphi_j),
  \\
  F_i &= (\varphi_i, f).
@f}
Before we move on with describing how these quantities can be computed, note
that if we had multiplied the original equation from the <i>right</i> by a
test function rather than from the left, then we would have obtained a linear
system of the form
@f{align*}
  U^T A = F
@f}
with a row vector $F$. By transposing this system, this is of course
equivalent to solving
@f{align*}
  A^T U = F
@f}
which here is the same as above since $A=A^T$ but in general is not. To avoid
any sort of confusion, experience has shown that simply getting into the habit
of multiplying the equation from the left rather than from the right (as is
often done in the mathematical literature) avoids a common class of errors as
the matrix is automatically correct and does not need to be transposed when
comparing theory and implementation. See step-9 for the first example in this
tutorial where we have a non-symmetric bilinear form for which it makes a
difference whether we multiply from the right or from the left.

Now we know what we need (namely objects that hold the matrix and
vectors, as well as ways to compute $A_{ij},F_i$), and we can look at what it
takes to make that happen:

- The objects for $A,U,F$ are of type SparseMatrix and Vector, and we will see
  in the program below what classes are used to solve linear systems.
- We need a way to form the integrals. In the finite element method, this is
  most commonly done using quadrature, i.e. the integrals are replaced by a
  weighted sum over a set of points on each cell. That is, we first split the
  integral over $\Omega$ into integrals over all cells,
  @f{align*}
    A_{ij} &= (\nabla\varphi_i, \nabla \varphi_j)
    = \sum_{K \in {\mathbb T}} \int_K \nabla\varphi_i \cdot \nabla \varphi_j,
    \\
    F_i &= (\varphi_i, f)
    = \sum_{K \in {\mathbb T}} \int_K \varphi_i f,
  @f}
  and then approximate each cell's contribution by quadrature:
  @f{align*}
    A^K_{ij} &=
    \int_K \nabla\varphi_i \cdot \nabla \varphi_j
    \approx
    \sum_q \nabla\varphi_i(\mathbf x^K_q) \cdot \nabla
    \varphi_j(\mathbf x^K_q) w_q^K,
    \\
    F^K_i &=
    \int_K \varphi_i f
    \approx
    \sum_q \varphi_i(\mathbf x^K_q) f(\mathbf x^K_q) w^K_q,
  @f}
  where $\mathbf x^K_q$ is the $q$th quadrature point on cell $K$, and $w^K_q$
  the $q$th quadrature weight. There are different parts to what is needed in
  doing this, and we will discuss them in turn next.
- First, we need a way to describe the location $\mathbf x_q^K$ of quadrature
  points and their weights $w^K_q$. They are usually mapped from the reference
  cell in the same way as shape functions, i.e., implicitly using the
  MappingQ1 class or, if you explicitly say so, through one of the other
  classes derived from Mapping. The locations and weights on the reference
  cell are described by objects derived from the Quadrature base
  class. Typically, one chooses a quadrature formula (i.e. a set of points and
  weights) so that the quadrature exactly equals the integral in the matrix;
  this can be achieved because all factors in the integral are polynomial, and
  is done by Gaussian quadrature formulas, implemented in the QGauss class.
- We then need something that can help us evaluate $\varphi_i(\mathbf x^K_q)$
  on cell $K$. This is what the FEValues class does: it takes a finite element
  objects to describe $\varphi$ on the reference cell, a quadrature object to
  describe the quadrature points and weights, and a mapping object (or
  implicitly takes the MappingQ1 class) and provides values and derivatives of
  the shape functions on the real cell $K$ as well as all sorts of other
  information needed for integration, at the quadrature points located on $K$.

FEValues really is the central class in the assembly process. One way you can
view it is as follows: The FiniteElement and derived classes describe shape
<i>functions</i>, i.e., infinite dimensional objects: functions have values at
every point. We need this for theoretical reasons because we want to perform
our analysis with integrals over functions. However, for a computer, this is a
very difficult concept, since they can in general only deal with a finite
amount of information, and so we replace integrals by sums over quadrature
points that we obtain by mapping (the Mapping object) using  points defined on
a reference cell (the Quadrature object) onto points on the real cell. In
essence, we reduce the problem to one where we only need a finite amount of
information, namely shape function values and derivatives, quadrature weights,
normal vectors, etc, exclusively at a finite set of points. The FEValues class
is the one that brings the three components together and provides this finite
set of information on a particular cell $K$. You will see it in action when we
assemble the linear system below.

It is noteworthy that all of this could also be achieved if you simply created
these three objects yourself in an application program, and juggled the
information yourself. However, this would neither be simpler (the FEValues
class provides exactly the kind of information you actually need) nor faster:
the FEValues class is highly optimized to only compute on each cell the
particular information you need; if anything can be re-used from the previous
cell, then it will do so, and there is a lot of code in that class to make
sure things are cached wherever this is advantageous.

The final piece of this introduction is to mention that after a linear
system is obtained, it is solved using an iterative solver and then
postprocessed: we create an output file using the DataOut class that can then
be visualized using one of the common visualization programs.

@note The preceding overview of all the important steps of any finite element
implementation has its counterpart in deal.II: The library can naturally be
grouped into a number of "modules" that cover the basic concepts just
outlined. You can access these modules through the tab at the top of this
page. An overview of the most fundamental groups of concepts is also available
on the <a href="index.html">front page of the deal.II manual</a>.


<h3>About the implementation</h3>

Although this is the simplest possible equation you can solve using the finite
element method, this program shows the basic structure of most finite
element programs and also serves as the template that almost all of the
following programs will essentially follow. Specifically, the main class of
this program looks like this:
@code
class Step3
{
  public:
    Step3 ();
    void run ();

  private:
    void make_grid ();
    void setup_system ();
    void assemble_system ();
    void solve ();
    void output_results () const;

    Triangulation<2>     triangulation;
    FE_Q<2>              fe;
    DoFHandler<2>        dof_handler;

    SparsityPattern      sparsity_pattern;
    SparseMatrix<double> system_matrix;
    Vector<double>       solution;
    Vector<double>       system_rhs;
};
@endcode

This follows the object oriented programming mantra of <a
href="http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)">data
encapsulation</a>, i.e. we do our best to hide almost all internal details of
this class in private members that are not accessible to the outside.

Let's start with the member variables: These follow the building blocks we
have outlined above in the bullet points, namely we need a Triangulation and a
DoFHandler object, and a finite element object that describes the kinds of
shape functions we want to use. The second group of objects relate to the
linear algebra: the system matrix and right hand side as well as the solution
vector, and an object that describes the sparsity pattern of the matrix. This
is all this class needs (and the essentials that any solver for a stationary
PDE requires) and that needs to survive throughout the entire program. In
contrast to this, the FEValues object we need for assembly is only required
throughout assembly, and so we create it as a local object in the function
that does that and destroy it again at its end.

Secondly, let's look at the member functions. These, as well, already form the
common structure that almost all following tutorial programs will use:
<ul>
  <li> <code>make_grid()</code>: This is what one could call a
       <i>preprocessing function</i>. As its name suggests, it sets up the
       object that stores the triangulation. In later examples, it could also
       deal with boundary conditions, geometries, etc.
  <li> <code>setup_system()</code>: This then is the function in which all the
       other data structures are set up that are needed to solve the
       problem. In particular, it will initialize the DoFHandler object and
       correctly size the various objects that have to do with the linear
       algebra. This function is often separated from the preprocessing
       function above because, in a time dependent program, it may be called
       at least every few time steps whenever the mesh
       is adaptively refined (something we will see how to do in step-6). On
       the other hand, setting up the mesh itself in the preprocessing
       function above is done only once at the beginning of the program and
       is, therefore, separated into its own function.
  <li> <code>assemble_system()</code>: This, then is where the contents of the
       matrix and right hand side are computed, as discussed at length in the
       introduction above. Since doing something with this linear system is
       conceptually very different from computing its entries, we separate it
       from the following function.
  <li> <code>solve()</code>: This then is the function in which we compute the
       solution $U$ of the linear system $AU=F$. In the current program, this
       is a simple task since the matrix is so simple, but it will become a
       significant part of a program's size whenever the problem is not so
       trivial any more (see, for example, step-20, step-22, or step-31 once
       you've learned a bit more about the library).
  <li> <code>output_results()</code>: Finally, when you have computed a
       solution, you probably want to do something with it. For example, you
       may want to output it in a format that can be visualized, or you may
       want to compute quantities you are interested in: say, heat fluxes in a
       heat exchanger, air friction coefficients of a wing, maximum bridge
       loads, or simple the value of the numerical solution at a point. This
       function is therefore the place for postprocessing your solution.
</ul>
All of this is held together by the single public function (other than the
constructor), namely the <code>run()</code> function. It is the one that is
called from the place where an object of this type is created, and it is the
one that calls all the other functions in their proper order. Encapsulating
this operation into the <code>run()</code> function, rather than calling all
the other functions from <code>main()</code> makes sure that you
can change how the separation of concerns within this class is
implemented. For example, if one of the functions becomes too big, you can
split it up into two, and the only places you have to be concerned about
changing as a consequence are within this very same class, and not anywhere
else.

As mentioned above, you will see this general structure &mdash; sometimes with
variants in spelling of the functions' names, but in essentially this order of
separation of functionality &mdash; again in many of the
following tutorial programs.


<h3> A note on types </h3>

deal.II defines a number of integral %types via <code>typedef</code>s in
namespace types. In particular, in this program you will see
types::global_dof_index in a couple of places: an integer type that is used to
denote the <i>global</i> index of a degree of freedom, i.e., the index of a
particular degree of freedom within the DoFHandler object that is defined on
top of a triangulation (as opposed to the index of a particular degree of
freedom within a particular cell). For the current program
(as well as almost all of the tutorial programs), you will have a few thousand
to maybe a few million unknowns globally (and, for $Q_1$ elements, you will
have 4 <i>locally on each cell</i> in 2d and 8 in 3d). Consequently, a data
type that allows to store sufficiently large numbers for global DoF indices is
<code>unsigned int</code> given that it allows to store numbers between 0 and
slightly more than 4 billion (on most systems, where integers are 32-bit). In
fact, this is what types::global_dof_index is.

So, why not just use <code>unsigned int</code> right away? deal.II used to do
this until version 7.3. However, deal.II supports very large computations (via
the framework discussed in step-40) that may have more than 4 billion unknowns
when spread across a few thousand processors. Consequently, there are
situations where <code>unsigned int</code> is not sufficiently large and we
need a 64-bit unsigned integral type. To make this possible, we introduced
types::global_dof_index which by default is defined as simply <code>unsigned
int</code> whereas it is possible to define it as <code>unsigned long long
int</code> if necessary, by passing a particular flag during configuration
(see the ReadMe file).

This covers the technical aspect. But there is also a documentation purpose:
everywhere in the library and codes that are built on it, if you see a place
using the data type types::global_dof_index, you immediately know that the
quantity that is being referenced is, in fact, a global dof index. No such
meaning would be apparent if we had just used <code>unsigned int</code> (which
may also be a local index, a boundary indicator, a material id,
etc.). Immediately knowing what a variable refers to also helps avoid errors:
it's quite clear that there must be a bug if you see an object of type
types::global_dof_index being assigned to variable of type
types::subdomain_id, even though they are both represented by unsigned
integers and the compiler will, consequently, not complain.

In more practical terms what the presence of this type means is that during
assembly, we create a $4\times 4$ matrix (in 2d, using a $Q_1$ element) of the
contributions of the cell we are currently sitting on, and then we need to add
the elements of this matrix to the appropriate elements of the global (system)
matrix. For this, we need to get at the global indices of the degrees of
freedom that are local to the current cell, for which we will always use the
following piece of the code:
@code
  cell->get_dof_indices (local_dof_indices);
@endcode
where <code>local_dof_indices</code> is declared as
@code
  std::vector<types::global_dof_index> local_dof_indices (fe.dofs_per_cell);
@endcode
The name of this variable might be a bit of a misnomer -- it stands for "the
global indices of those degrees of freedom locally defined on the current
cell" -- but variables that hold this information are universally named this
way throughout the library.

@note types::global_dof_index is not the only type defined in this
namespace. Rather, there is a whole family, including types::subdomain_id,
types::boundary_id, and types::material_id. All of these are
<code>typedef</code>s for integer data types but, as explained above, they are
used throughout the library so that (i) the intent of a variable becomes more
easily discerned, and (ii) so that it becomes possible to change the actual
type to a larger one if necessary without having to go through the entire
library and figure out whether a particular use of <code>unsigned int</code>
corresponds to, say, a material indicator.

