HyTeG
Matrix-Free Finite Elements
|
In this tutorial, we solve the Poisson equation using a discontinuous Galerkin discretization and adaptive mesh refinement.
The setup is taken from Elman, H. C., Silvester, D. J., & Wathen, A. J. (2014). Finite elements and fast iterative solvers: with applications in incompressible fluid dynamics. It is a standard test case that introduces a singularity at the origin. Due to this singularity, regular global refinement does not meet the expected optimal a priori error estimates. This issue is in practice usually circumvented by adaptive local refinement around the singularity.
The analytical solution to the Poisson equation
\[ \begin{eqnarray*} - \Delta u = f \end{eqnarray*} \]
is given in polar coordinates by
\[ \begin{align*} u(r, \theta) &= r^{2/3} \sin( (2 \theta + \pi) / 3 ), \\ f &= 0. \end{align*} \]
This tutorial demonstrates how adaptive mesh refinement (AMR) is applied together with the discontinuous Galerkin method. For details on the discretization we refer to the literature, for example Rivière, B. (2008). Discontinuous Galerkin methods for solving elliptic and parabolic equations: theory and implementation.
We first create the PrimitiveStorage from a mesh file has has been done in previous examples.
Mesh refinement procedures can be split into two types.
In this tutorial we cover the second case - and thus apply a discontinuous Galerkin discretization to the problem. However, the first method is also applicable in HyTeG.
The refinement is applied directly to the PrimitiveStorage and yields a tree-like structure. When a (volume-)primitive is refined, child primitives are created. In 2D, faces are split into 4 face primitives, in 3D cells are split into 8 cell primitives. This works as described in Bey, J. (1995). Tetrahedral grid refinement.
The algorithm, however, is restricted to maintain a 2:1 balance between neighboring volume primitives. That means the refinement levels of neighboring macros can only differ by 1. Before the refinement is applied, the marked primitives are passed to a function that marks further primitives for refinement if necessary to keep the 2:1 balance.
All of this happens in one method. It requires only to pass the PrimitiveID of all (local) volume primitives to be refined.
In this example we simply refine all primitives that have a vertex at the origin multiple times. The result looks like this:
In a second step, these coarse grids are refined uniformly.
DG functions and operators are almost used as it's done for other conforming discretizations. The main difference is that the basis and degree are passed in the constructor. This also applied for the operators - the form has to be passed here, too.
The weak enforcement of Dirichlet boundary conditions is handled by a function that also takes as an argument the Form object.
Interpolation of functions into the finite element space is currently handled by solution of the system
\[ \begin{eqnarray*} M u = (f, v)_\Omega \end{eqnarray*} \]
That requires the solution of a linear system involving the mass matrix \( M \):
Eventually, we solve the linear system and plot the error over \( \frac{1}{h} \).
Standard global refinement is not sufficient to retain the optimal asymptotic accuracy. But with aggressive local refinement the accuracy can be recovered.