diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index fbf20b2458099cde5fd04af2561380804f40aedb..aacf28405d7293db3555bf49083ee4b425b9947c 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(2pinfiltration)
 add_subdirectory(1ptracer)
 add_subdirectory(biomineralization)
+add_subdirectory(cahn_hilliard)
 add_subdirectory(diffusion)
 add_subdirectory(embedded_network_1d3d)
 add_subdirectory(shallowwaterfriction)
diff --git a/examples/README.md b/examples/README.md
index beb935118d8db8a5d64f7bcedeb2a8c74f17f499..029c5781ca6ac0dfa9839919b7ebad34b02770e8 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -22,12 +22,35 @@ __Model equations:__ A diffusion equation model fully developed and contained wi
 __Discretization method:__ Vertex-centered finite volumes / control-volume finite elements (Lagrange, P1) (`BoxModel`)
 
 </td>
-<td width="35%"><a href="diffusion/README.md">
+<td width="25%"><a href="diffusion/README.md">
 <figure><img src="diffusion/img/diffusion.gif" alt="diffusion"/></figure></td>
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 2: One-phase flow and tracer transport](1ptracer/README.md)
+### [:open_file_folder: Example 2: Cahn-Hilliard equation](cahn_hilliard/README.md)
+
+<table><tr><td>
+
+In this example we simulate the separation of two immiscible phases using the Cahn-Hilliard equation.
+
+You learn how to
+
+* setup a new nonlinear model equation (Cahn-Hilliard equation)
+* setup a model with two governing equations
+* implement a custom volume variables class to name variables
+* generate a randomly distributed vector-valued initial field (with MPI parallelism)
+* solve a time-dependent diffusion problem in parallel
+
+__Model equations:__ A Cahn-Hilliard equation model fully developed and contained within the example<br />
+__Discretization method:__ Vertex-centered finite volumes / control-volume finite elements (Lagrange, P1) (`BoxModel`)
+
+</td>
+<td width="25%"><a href="cahn_hilliard/README.md">
+<figure><img src="cahn_hilliard/img/animation.gif" alt="phase distribution" width="400px"/></figure></td>
+</a></td>
+</tr></table>
+
+### [:open_file_folder: Example 3: One-phase flow and tracer transport](1ptracer/README.md)
 
 <table><tr><td>
 
@@ -51,7 +74,7 @@ __Discretization method:__ Cell-centered finite volumes with two-point flux appr
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 3: Two-phase flow with infiltration and adaptive grid](2pinfiltration/README.md)
+### [:open_file_folder: Example 4: Two-phase flow with infiltration and adaptive grid](2pinfiltration/README.md)
 
 <table><tr><td>
 
@@ -75,7 +98,7 @@ __Discretization method:__ Cell-centered finite volumes with two-point flux appr
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 4: Shallow water model](shallowwaterfriction/README.md)
+### [:open_file_folder: Example 5: Shallow water model](shallowwaterfriction/README.md)
 
 <table><tr><td>
 
@@ -95,7 +118,7 @@ __Discretization method:__ Cell-centered finite volumes with Riemann solver (`CC
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 5: Freeflow channel](freeflowchannel/README.md)
+### [:open_file_folder: Example 6: Freeflow channel](freeflowchannel/README.md)
 
 <table><tr><td>
 
@@ -115,7 +138,7 @@ __Discretization method:__ Finite volumes with staggered grid arrangement (`Stag
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 6: One-phase flow with rotation-symmetric solution](1protationsymmetry/README.md)
+### [:open_file_folder: Example 7: One-phase flow with rotation-symmetric solution](1protationsymmetry/README.md)
 
 <table><tr><td>
 
@@ -136,7 +159,7 @@ __Discretization method:__ Vertex-centered finite volumes / control-volume finit
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 7: Biomineralization](biomineralization/README.md)
+### [:open_file_folder: Example 8: Biomineralization](biomineralization/README.md)
 
 <table><tr><td>
 
@@ -161,7 +184,7 @@ __Discretization method:__ Vertex-centered finite volumes / control-volume finit
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 8: Lid-driven cavity](liddrivencavity/README.md)
+### [:open_file_folder: Example 9: Lid-driven cavity](liddrivencavity/README.md)
 
 <table><tr><td>
 
@@ -182,7 +205,7 @@ __Discretization method:__ Finite volumes with staggered grid arrangement (`Stag
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 9: Permeability estimation using a pore-network model](porenetwork_upscaling/README.md)
+### [:open_file_folder: Example 10: Permeability estimation using a pore-network model](porenetwork_upscaling/README.md)
 
 <table><tr><td>
 
@@ -203,7 +226,7 @@ __Discretization method:__ Pore-network (`PoreNetworkModel`)
 </a></td>
 </tr></table>
 
-### [:open_file_folder: Example 10: Embedded network 1D-3D model (tissue perfusion)](embedded_network_1d3d/README.md)
+### [:open_file_folder: Example 11: Embedded network 1D-3D model (tissue perfusion)](embedded_network_1d3d/README.md)
 
 <table><tr><td>
 
diff --git a/examples/cahn_hilliard/.doc_config b/examples/cahn_hilliard/.doc_config
new file mode 100644
index 0000000000000000000000000000000000000000..6df89661cd20ce69ae526ae0f44fd3baf4a89b5e
--- /dev/null
+++ b/examples/cahn_hilliard/.doc_config
@@ -0,0 +1,27 @@
+{
+    "README.md" : [
+        "doc/_intro.md"
+    ],
+
+    "doc/model.md" : [
+        "doc/_model.md",
+        "model.hh"
+    ],
+
+    "doc/main.md" : [
+        "doc/_main.md",
+        "main.cc"
+    ],
+
+    "navigation" : {
+        "mainpage" : "README.md",
+        "subpages" : [
+            "doc/model.md",
+            "doc/main.md"
+        ],
+        "subtitles" : [
+            "Model implementation",
+            "Main program"
+        ]
+    }
+}
diff --git a/examples/cahn_hilliard/CMakeLists.txt b/examples/cahn_hilliard/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f69a567fda9d580add84414e8939f4a7bec35582
--- /dev/null
+++ b/examples/cahn_hilliard/CMakeLists.txt
@@ -0,0 +1,27 @@
+dune_symlink_to_source_files(FILES "params.input")
+
+# A simple test to automatically check the example compiles and produces the same result
+dumux_add_test(NAME example_cahn_hilliard
+               LABELS example
+               SOURCES main.cc
+               COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+               CMD_ARGS --script fuzzy
+                        --files ${CMAKE_SOURCE_DIR}/test/references/example_cahn_hilliard-reference.vtu
+                                ${CMAKE_CURRENT_BINARY_DIR}/cahn_hilliard-00102.vtu
+                        --command "${CMAKE_CURRENT_BINARY_DIR}/example_cahn_hilliard params.input
+                        -Grid.Cells \" 10 10\" -Problem.Mobility 0.01 -Problem.SurfaceTension 0.5")
+
+dumux_add_test(NAME example_cahn_hilliard_parallel
+               LABELS example
+               TARGET example_cahn_hilliard
+               CMAKE_GUARD MPI_FOUND
+               COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+               CMD_ARGS --script fuzzy
+                        --files ${CMAKE_SOURCE_DIR}/test/references/example_cahn_hilliard_parallel_p0-reference.vtu
+                                ${CMAKE_CURRENT_BINARY_DIR}/s0002-p0000-cahn_hilliard_parallel-00102.vtu
+                                ${CMAKE_SOURCE_DIR}/test/references/example_cahn_hilliard_parallel_p1-reference.vtu
+                                ${CMAKE_CURRENT_BINARY_DIR}/s0002-p0001-cahn_hilliard_parallel-00102.vtu
+                        --command "${MPIEXEC} -np 2
+                        ${CMAKE_CURRENT_BINARY_DIR}/example_cahn_hilliard params.input
+                        -Problem.Name cahn_hilliard_parallel
+                        -Grid.Cells \" 10 10\" -Problem.Mobility 0.01 -Problem.SurfaceTension 0.5")
diff --git a/examples/cahn_hilliard/README.md b/examples/cahn_hilliard/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..11552d371170e8184917058c461b43e2a353c6d5
--- /dev/null
+++ b/examples/cahn_hilliard/README.md
@@ -0,0 +1,127 @@
+<!-- Important: This file has been automatically generated by generate_example_docs.py. Do not edit this file directly! -->
+
+# Cahn-Hilliard equation
+
+In this example, we create an application solving the Cahn-Hilliard equation which describes
+a phase separation process.
+This example is implemented in three files, [`model.hh`](model.hh), [`params.input`](params.input), [`main.cc`](main.cc).
+The [`model.hh`](model.hh) header implements a simple self-contained Cahn-Hilliard equation model
+to be used with a control-volume finite element discretization like the Box method.
+The [`main.cc`](main.cc) source file contains the main program and [`params.input`](params.input) contains
+runtime parameters. The executable is configured in [`CMakeLists.txt`](CMakeLists.txt) and created with CMake.
+The source code will be discussed in Part 1 and Part 2 after an introduction to the equations and the problem description.
+
+__The main points illustrated in this example are__
+
+* setting up a model with two coupled nonlinear equations
+* creating a vector-valued random initial solution in parallel
+* solving a time-dependent nonlinear problem
+* using a Newton solver instance
+* enabling partial reassembly for the Newton method
+* using adaptive time stepping
+
+__Results__. The result will look like below.
+
+<figure>
+    <center>
+        <img src="img/animation.gif" alt="Cahn Hilliard result" width="400px"/>
+        <figcaption> <b> Fig.1 </b> - Evolution of an initially random concentration field according to the Cahn-Hilliard equation.</figcaption>
+    </center>
+</figure>
+
+__Table of contents__. This description is structured as follows:
+
+[TOC]
+
+## Equation and problem description
+
+The Cahn-Hilliard equation is a forth order partial differential equation (PDE) and reads
+
+```math
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla\left[ \frac{\partial f}{\partial c} - \gamma \nabla^2 c \right]\right) = 0 \quad \text{in} \; \Omega \times (0, T]
+```
+
+with the concentration $c(x,t)$, the mobility coefficient $M$, and surface tension $\gamma$.
+The domain $\Omega \subset \mathbb{R}^2$ is initialized with a concentration field
+$c(x,t=0) = 0.42 + \zeta$, randomly perturbed by
+noise $\zeta$ following a uniform distribution $\zeta \sim U(-0.02, 0.02)$.
+With time the concentration field evolves towards attaining mostly values near to $0$ or $1$ while
+conserving the total concentration. The model describes the separation of two immiscible fluids.
+
+The fourth order PDE cannot be solved by a standard finite volume scheme. We therefore
+split the equation in two second order PDEs
+
+```math
+\begin{aligned}
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla \mu \right) &= 0\\
+- \gamma \nabla^2 c &= \mu - \frac{\partial f}{\partial c}.
+\end{aligned}
+```
+
+were $\mu$ is called chemical potential.
+Using the free energy functional $f = E c^2(1-c)^2$, where $E$ is a scaling parameter,
+we obtain
+
+```math
+\begin{aligned}
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla \mu \right) &= 0\\
+- \gamma \nabla^2 c &= \mu - E (4 c^3 - 6 c^2 +2 c).
+\end{aligned}
+```
+
+The concentration field is conserved and
+evolves with a flux proportional to $\nabla \mu$, while the latter depends on the Laplacian of
+the concentration $\nabla^2 c$ and the free energy functional which is a nonlinear function of $c$. We therefore have a system of two coupled nonlinear PDEs. We will use homogeneous Neumann
+boundary conditions everywhere on $\partial \Omega$. This means that the total concentration in $\Omega$ stays constant.
+
+For the implementation, it is useful to write the conservation equation in the following abstract
+form in vector notation,
+
+```math
+\frac{\partial \boldsymbol{S}(\boldsymbol{U})}{\partial t} + \nabla\cdot \boldsymbol{F}(\boldsymbol{U}) = \boldsymbol{Q}(\boldsymbol{U})
+```
+
+where for the Cahn-Hillard equation, we have
+
+```math
+\boldsymbol{U} := \begin{bmatrix} c \\ \mu \end{bmatrix}, \quad
+\boldsymbol{S}(\boldsymbol{U}) := \begin{bmatrix} c \\ 0 \end{bmatrix}, \quad
+\boldsymbol{F}(\boldsymbol{U}) := \begin{bmatrix} -M \nabla \mu \\ -\gamma \nabla c \end{bmatrix}, \quad
+\boldsymbol{Q}(\boldsymbol{U}) := \begin{bmatrix} 0 \\ \mu - E (4 c^3 - 6 c^2 +2 c) \end{bmatrix}.
+```
+
+### Model parameters
+
+* $\Omega = [0,1]\times[0,1]$ (unit square)
+* End time $T = 1$, initial time step size $\Delta t = 0.0025$, and maximum time step size $\Delta t = 0.01$
+* $100 \times 100$ cells (structured Cartesian grid)
+* $M = 0.0001$
+* $\gamma = 0.01$
+* $f = E c^2(1-c)^2$, with $E = 100$
+* $c^0_{h,B} = 0.42 + \zeta$, where $\zeta \sim U(-0.02,0.02)$
+* $\mu^0_{h,B} = 0.0$
+* homogeneous Neumann boundary conditions
+
+### Running the example in parallel
+
+See [Diffusion equation example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/README.md).
+
+# Implementation
+
+For this example the C++ code is contained in two files, [`model.hh`](model.hh) and [`main.cc`](main.cc). The [`model.hh`](model.hh) header contains the `ModelTraits` and properties for the
+model type tag `CahnHilliardModel`, as well as the volume variables class
+`CahnHilliardModelVolumeVariables` and the local residual class `CahnHilliardModelLocalResidual`.
+The source term is extended in the problem definition `CahnHilliardTestProblem`
+in the file `main.cc`, which also contains more specific properties of the problem setup (for
+type tag `CahnHilliardTest`) as well as the actual simulation loop usually found in the main function.
+
+## Part 1: Model implementation
+
+| [:arrow_right: Click to continue with part 1 of the documentation](doc/model.md) |
+|---:|
+
+
+## Part 2: Main program
+
+| [:arrow_right: Click to continue with part 2 of the documentation](doc/main.md) |
+|---:|
diff --git a/examples/cahn_hilliard/doc/_intro.md b/examples/cahn_hilliard/doc/_intro.md
new file mode 100644
index 0000000000000000000000000000000000000000..42f94f6c00ef5c09d5439112abc854ce91748f5a
--- /dev/null
+++ b/examples/cahn_hilliard/doc/_intro.md
@@ -0,0 +1,114 @@
+# Cahn-Hilliard equation
+
+In this example, we create an application solving the Cahn-Hilliard equation which describes
+a phase separation process.
+This example is implemented in three files, [`model.hh`](model.hh), [`params.input`](params.input), [`main.cc`](main.cc).
+The [`model.hh`](model.hh) header implements a simple self-contained Cahn-Hilliard equation model
+to be used with a control-volume finite element discretization like the Box method.
+The [`main.cc`](main.cc) source file contains the main program and [`params.input`](params.input) contains
+runtime parameters. The executable is configured in [`CMakeLists.txt`](CMakeLists.txt) and created with CMake.
+The source code will be discussed in Part 1 and Part 2 after an introduction to the equations and the problem description.
+
+__The main points illustrated in this example are__
+
+* setting up a model with two coupled nonlinear equations
+* creating a vector-valued random initial solution in parallel
+* solving a time-dependent nonlinear problem
+* using a Newton solver instance
+* enabling partial reassembly for the Newton method
+* using adaptive time stepping
+
+__Results__. The result will look like below.
+
+<figure>
+    <center>
+        <img src="img/animation.gif" alt="Cahn Hilliard result" width="400px"/>
+        <figcaption> <b> Fig.1 </b> - Evolution of an initially random concentration field according to the Cahn-Hilliard equation.</figcaption>
+    </center>
+</figure>
+
+__Table of contents__. This description is structured as follows:
+
+[TOC]
+
+## Equation and problem description
+
+The Cahn-Hilliard equation is a forth order partial differential equation (PDE) and reads
+
+```math
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla\left[ \frac{\partial f}{\partial c} - \gamma \nabla^2 c \right]\right) = 0 \quad \text{in} \; \Omega \times (0, T]
+```
+
+with the concentration $c(x,t)$, the mobility coefficient $M$, and surface tension $\gamma$.
+The domain $\Omega \subset \mathbb{R}^2$ is initialized with a concentration field
+$c(x,t=0) = 0.42 + \zeta$, randomly perturbed by
+noise $\zeta$ following a uniform distribution $\zeta \sim U(-0.02, 0.02)$.
+With time the concentration field evolves towards attaining mostly values near to $0$ or $1$ while
+conserving the total concentration. The model describes the separation of two immiscible fluids.
+
+The fourth order PDE cannot be solved by a standard finite volume scheme. We therefore
+split the equation in two second order PDEs
+
+```math
+\begin{aligned}
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla \mu \right) &= 0\\
+- \gamma \nabla^2 c &= \mu - \frac{\partial f}{\partial c}.
+\end{aligned}
+```
+
+were $\mu$ is called chemical potential.
+Using the free energy functional $f = E c^2(1-c)^2$, where $E$ is a scaling parameter,
+we obtain
+
+```math
+\begin{aligned}
+\frac{\partial c}{\partial t} - \nabla\cdot \left( M \nabla \mu \right) &= 0\\
+- \gamma \nabla^2 c &= \mu - E (4 c^3 - 6 c^2 +2 c).
+\end{aligned}
+```
+
+The concentration field is conserved and
+evolves with a flux proportional to $\nabla \mu$, while the latter depends on the Laplacian of
+the concentration $\nabla^2 c$ and the free energy functional which is a nonlinear function of $c$. We therefore have a system of two coupled nonlinear PDEs. We will use homogeneous Neumann
+boundary conditions everywhere on $\partial \Omega$. This means that the total concentration in $\Omega$ stays constant.
+
+For the implementation, it is useful to write the conservation equation in the following abstract
+form in vector notation,
+
+```math
+\frac{\partial \boldsymbol{S}(\boldsymbol{U})}{\partial t} + \nabla\cdot \boldsymbol{F}(\boldsymbol{U}) = \boldsymbol{Q}(\boldsymbol{U})
+```
+
+where for the Cahn-Hillard equation, we have
+
+```math
+\boldsymbol{U} := \begin{bmatrix} c \\ \mu \end{bmatrix}, \quad
+\boldsymbol{S}(\boldsymbol{U}) := \begin{bmatrix} c \\ 0 \end{bmatrix}, \quad
+\boldsymbol{F}(\boldsymbol{U}) := \begin{bmatrix} -M \nabla \mu \\ -\gamma \nabla c \end{bmatrix}, \quad
+\boldsymbol{Q}(\boldsymbol{U}) := \begin{bmatrix} 0 \\ \mu - E (4 c^3 - 6 c^2 +2 c) \end{bmatrix}.
+```
+
+### Model parameters
+
+* $\Omega = [0,1]\times[0,1]$ (unit square)
+* End time $T = 1$, initial time step size $\Delta t = 0.0025$, and maximum time step size $\Delta t = 0.01$
+* $100 \times 100$ cells (structured Cartesian grid)
+* $M = 0.0001$
+* $\gamma = 0.01$
+* $f = E c^2(1-c)^2$, with $E = 100$
+* $c^0_{h,B} = 0.42 + \zeta$, where $\zeta \sim U(-0.02,0.02)$
+* $\mu^0_{h,B} = 0.0$
+* homogeneous Neumann boundary conditions
+
+### Running the example in parallel
+
+See [Diffusion equation example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/README.md).
+
+# Implementation
+
+For this example the C++ code is contained in two files, [`model.hh`](model.hh) and [`main.cc`](main.cc). The [`model.hh`](model.hh) header contains the `ModelTraits` and properties for the
+model type tag `CahnHilliardModel`, as well as the volume variables class
+`CahnHilliardModelVolumeVariables` and the local residual class `CahnHilliardModelLocalResidual`.
+The source term is extended in the problem definition `CahnHilliardTestProblem`
+in the file `main.cc`, which also contains more specific properties of the problem setup (for
+type tag `CahnHilliardTest`) as well as the actual simulation loop usually found in the main function.
diff --git a/examples/cahn_hilliard/doc/_main.md b/examples/cahn_hilliard/doc/_main.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/examples/cahn_hilliard/doc/_model.md b/examples/cahn_hilliard/doc/_model.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/examples/cahn_hilliard/doc/main.md b/examples/cahn_hilliard/doc/main.md
new file mode 100644
index 0000000000000000000000000000000000000000..778b01e7616ba460060b8ff8eb9f0db9282f88f4
--- /dev/null
+++ b/examples/cahn_hilliard/doc/main.md
@@ -0,0 +1,402 @@
+<!-- Important: This file has been automatically generated by generate_example_docs.py. Do not edit this file directly! -->
+
+
+| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_left: Go back to part 1](model.md) |
+|---|---:|
+
+
+
+# Cahn-Hilliard equation main program
+
+The file [`main.cc`](main.cc) contains the problem class `CahnHilliardTestProblem`,
+properties and traits specific to the test case as well as the `main` function.
+The setup consists of four steps:
+1. Define the problem setting boundary conditions and the diffusion coefficient
+2. Configure the property system reusing the model defined in Part 1
+3. Define a function for setting the random initial condition
+4. The main program defining all steps of the program
+
+__Table of contents__
+
+[TOC]
+
+We start in `main.cc` with the necessary header includes:
+<details><summary> Click to show includes</summary>
+
+```cpp
+
+#include <config.h>
+#include <type_traits>
+#include <random>
+
+#include <dumux/common/initialize.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/numeqvector.hh>
+#include <dumux/common/boundarytypes.hh>
+#include <dumux/common/fvproblem.hh>
+
+#include <dumux/discretization/box.hh>
+#include <dumux/linear/linearsolvertraits.hh>
+#include <dumux/linear/linearalgebratraits.hh>
+#include <dumux/linear/istlsolvers.hh>
+#include <dumux/nonlinear/newtonsolver.hh>
+#include <dumux/assembly/fvassembler.hh>
+
+#include <dune/grid/yaspgrid.hh>
+#include <dumux/io/vtkoutputmodule.hh>
+#include <dumux/io/grid/gridmanager_yasp.hh>
+
+#include "model.hh"
+```
+
+</details>
+
+## 1. The problem class
+
+The problem class implements boundary conditions and the source term.
+It also provides an interface that is used by the local residual (see Part 1) to obtain
+the mobility and surface tension. The values are read from the parameter configuration tree.
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../main.cc))</summary>
+
+
+```cpp
+namespace Dumux {
+template<class TypeTag>
+class CahnHilliardTestProblem : public FVProblem<TypeTag>
+{
+```
+
+<details><summary> Click to show boilerplate code</summary>
+
+```cpp
+
+    using ParentType = FVProblem<TypeTag>;
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using FVElementGeometry = typename GridGeometry::LocalView;
+    using SubControlVolume = typename GridGeometry::SubControlVolume;
+    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
+    using Element = typename GridView::template Codim<0>::Entity;
+    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
+
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
+    using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
+    using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
+    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
+```
+
+</details>
+In the constructor, we read the parameter constants from the
+parameter tree (which is initialized with the content of `params.input`).
+
+```cpp
+public:
+    CahnHilliardTestProblem(std::shared_ptr<const GridGeometry> gridGeometry)
+    : ParentType(gridGeometry)
+    {
+        mobility_ = getParam<Scalar>("Problem.Mobility");
+        surfaceTension_ = getParam<Scalar>("Problem.SurfaceTension");
+        energyScale_ = getParam<Scalar>("Problem.EnergyScale");
+    }
+```
+
+In the `source` function, we implement the derivative of the free energy.
+This demonstrates how parts of the local residual can be split into model specific
+parts and parts that might change from scenario to scenario.
+
+```cpp
+    template<class ElementVolumeVariables>
+    NumEqVector source(const Element &element,
+                       const FVElementGeometry& fvGeometry,
+                       const ElementVolumeVariables& elemVolVars,
+                       const SubControlVolume &scv) const
+    {
+        NumEqVector values(0.0);
+        const auto& c = elemVolVars[scv].concentration();
+        values[Indices::chemicalPotentialEqIdx] = -energyScale_*2.0*c*(2.0*c*c - 3*c + 1);
+        return values;
+    }
+```
+
+For the boundary we choose boundary flux (or Neumann) conditions for all equations and on
+every part of the boundary, specifying zero flux everywhere for both equations.
+
+```cpp
+    BoundaryTypes boundaryTypesAtPos(const GlobalPosition& globalPos) const
+    {
+        BoundaryTypes values;
+        values.setAllNeumann();
+        return values;
+    }
+
+    NumEqVector neumannAtPos(const GlobalPosition& globalPos) const
+    { return { 0.0, 0.0 }; }
+```
+
+The parameters interfaces are used in the local residual (see Part 1).
+We can name this interface however we want as long as we adapt the calling site
+in the `LocalResidual` class in `model.hh`.
+
+```cpp
+    Scalar mobility() const
+    { return mobility_; }
+
+    Scalar surfaceTension() const
+    { return surfaceTension_; }
+
+private:
+    Scalar mobility_;
+    Scalar surfaceTension_;
+    Scalar energyScale_;
+};
+} // end namespace Dumux
+```
+
+
+</details>
+
+## 2. Property tag and specializations
+
+We create a new tag `DiffusionTest` that inherits all properties
+specialized for the tag `DiffusionModel` (we created this in Part 1)
+and the tag `BoxModel` which provides types relevant for the spatial
+discretization scheme (see [dumux/discretization/box.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/discretization/box.hh)).
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../main.cc))</summary>
+
+
+```cpp
+namespace Dumux::Properties::TTag {
+struct CahnHilliardTest
+{
+    using InheritsFrom = std::tuple<CahnHilliardModel, BoxModel>;
+
+    using Grid = Dune::YaspGrid<2>;
+
+    template<class TypeTag>
+    using Problem = CahnHilliardTestProblem<TypeTag>;
+
+    using EnableGridGeometryCache = std::true_type;
+    using EnableGridVolumeVariablesCache = std::true_type;
+    using EnableGridFluxVariablesCache = std::true_type;
+};
+} // end namespace Dumux::Properties
+```
+
+
+</details>
+
+## 3. Creating the initial solution
+
+To initialize with a random field in parallel, where each processor
+creates its own random number sequence, we need to communicate the
+resulting values on the processor border and overlap.
+See [Diffusion equation example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/docs/main.md).
+for details. Here in addition, we need to provide a custom scatter operation
+that handles vector types. We only need to communicate the first entry (concentration).
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../main.cc))</summary>
+
+
+```cpp
+// functor for data communication with MPI
+struct MinScatter
+{
+    template<class A, class B>
+    static void apply(A& a, const B& b)
+    { a[0] = std::min(a[0], b[0]); }
+};
+
+// create the random initial solution
+template<class SolutionVector, class GridGeometry>
+SolutionVector createInitialSolution(const GridGeometry& gg)
+{
+    SolutionVector sol(gg.numDofs());
+
+    // Generate random number and add processor offset
+    // For sequential runs `rank` always returns `0`.
+    std::mt19937 gen(0); // seed is 0 for deterministic results
+    std::uniform_real_distribution<> dis(0.0, 1.0);
+    for (int n = 0; n < sol.size(); ++n)
+    {
+        sol[n][0] = 0.42 + 0.02*(0.5-dis(gen)) + gg.gridView().comm().rank();
+        sol[n][1] = 0.0;
+    }
+
+    // We take the value of the processor with the minimum rank
+    // and subtract the rank offset
+    if (gg.gridView().comm().size() > 1)
+    {
+        Dumux::VectorCommDataHandle<
+            typename GridGeometry::VertexMapper,
+            SolutionVector,
+            GridGeometry::GridView::dimension,
+            MinScatter
+        > minHandle(gg.vertexMapper(), sol);
+        gg.gridView().communicate(minHandle, Dune::All_All_Interface, Dune::ForwardCommunication);
+
+        // Remove processor offset
+        for (int n = 0; n < sol.size(); ++n)
+            sol[n][0] -= std::floor(sol[n][0]);
+    }
+    return sol;
+}
+```
+
+
+</details>
+
+## 4. The main program
+
+The `main` function sets up the simulation framework, initializes runtime parameters,
+creates the grid and storage vectors
+for the variables, primary and secondary. It specifies and constructs and assembler, which
+assembles the discretized residual and system matrix (Jacobian of the model residual), as well as
+a linear solver. A Newton method is used to solve the nonlinear equations where in each Newton iteration
+the Jacobian and the residual needs to be reassembled and the resulting linear system is solved.
+The time loop controls the time stepping. Here, we let the Newton solver suggest an adaption of
+the time step size based on the convergence history of the nonlinear solver.
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../main.cc))</summary>
+
+
+```cpp
+int main(int argc, char** argv)
+{
+    using namespace Dumux;
+```
+
+We initialize MPI and/or multithreading backend. When not running
+in parallel the MPI setup is skipped.
+
+```cpp
+    Dumux::initialize(argc, argv);
+```
+
+Then we initialize parameter tree.
+
+```cpp
+    Parameters::init(argc, argv);
+```
+
+We create an alias for the type tag for this problem
+and extract type information through properties.
+
+```cpp
+    using TypeTag = Properties::TTag::CahnHilliardTest;
+
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using Grid = GetPropType<TypeTag, Properties::Grid>;
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
+    using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
+    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+```
+
+We initialize the grid, grid geometry, problem, solution vector, and grid variables.
+
+```cpp
+    GridManager<Grid> gridManager;
+    gridManager.init();
+
+    auto gridGeometry = std::make_shared<GridGeometry>(gridManager.grid().leafGridView());
+    auto problem = std::make_shared<Problem>(gridGeometry);
+    auto sol = createInitialSolution<SolutionVector>(*gridGeometry);
+    auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
+    gridVariables->init(sol);
+```
+
+We initialize the VTK output module and write out the initial concentration and chemical potential
+
+```cpp
+    VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name());
+    vtkWriter.addVolumeVariable([](const auto& vv){ return vv.concentration(); }, "c");
+    vtkWriter.addVolumeVariable([](const auto& vv){ return vv.chemicalPotential(); }, "mu");
+    vtkWriter.write(0.0);
+```
+
+We instantiate time loop using start and end time as well as
+the time step size from the parameter tree (`params.input`)
+
+```cpp
+    auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>(
+        getParam<Scalar>("TimeLoop.TStart", 0.0),
+        getParam<Scalar>("TimeLoop.InitialTimeStepSize"),
+        getParam<Scalar>("TimeLoop.TEnd")
+    );
+```
+
+We set the maximum time step size allowed in the adaptive time stepping scheme.
+
+```cpp
+    timeLoop->setMaxTimeStepSize(getParam<Scalar>("TimeLoop.MaxTimeStepSize"));
+```
+
+Next, we choose the type of assembler, linear solver and PDE solver
+and construct instances of these classes.
+
+```cpp
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    using LinearSolver = SSORBiCGSTABIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>;
+    using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>;
+
+    auto oldSol = sol;
+    auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol);
+    auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper());
+    Solver solver(assembler, linearSolver);
+```
+
+The time loop is where most of the actual computations happen.
+We assemble and solve the linear system of equations, update the solution,
+write the solution to a VTK file and continue until the we reach the
+final simulation time.
+
+
+```cpp
+    timeLoop->start(); do
+    {
+        // Assemble & solve
+        // Passing the time loop enables the solver to repeat the time step
+        // with a reduced time step size if the Newton solver does not converge.
+        solver.solve(sol, *timeLoop);
+
+        // make the new solution the old solution
+        oldSol = sol;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        // write VTK output (concentration field and chemical potential)
+        vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by the Newton solver
+        timeLoop->setTimeStepSize(solver.suggestTimeStepSize(timeLoop->timeStepSize()));
+
+    } while (!timeLoop->finished());
+
+    // print the final report
+    timeLoop->finalize(gridGeometry->gridView().comm());
+    return 0;
+}
+```
+
+
+</details>
+
+
+| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_left: Go back to part 1](model.md) |
+|---|---:|
+
diff --git a/examples/cahn_hilliard/doc/model.md b/examples/cahn_hilliard/doc/model.md
new file mode 100644
index 0000000000000000000000000000000000000000..b9fc2a3d73c708ec5b98ca65d705200c4c4af265
--- /dev/null
+++ b/examples/cahn_hilliard/doc/model.md
@@ -0,0 +1,357 @@
+<!-- Important: This file has been automatically generated by generate_example_docs.py. Do not edit this file directly! -->
+
+
+| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_right: Continue with part 2](main.md) |
+|---|---:|
+
+
+
+# Cahn-Hilliard equation model definition
+
+In the file `model.hh`, we define the model equations and
+set all default model properties. The setup consist of four steps:
+1. Create a model type tag (used to specialize properties)
+2. Define the volume variables class computing and storing variables for a control volume
+3. Define the local residual class implementing the discrete equation
+4. Specialize important properties of the model such that Dumux knows how to assemble the system matrix
+
+We implement the classes
+
+* `CahnHilliardModel` (step 1),
+* `CahnHilliardModelVolumeVariables` (step 2) and
+* `CahnHilliardModelLocalResidual` (step 3).
+
+__Table of contents__
+
+[TOC]
+
+We start in `model.hh` with the necessary header includes:
+<details><summary> Click to show includes</summary>
+
+```cpp
+
+#include <dumux/common/math.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/numeqvector.hh>
+```
+
+</details>
+
+## 1. Property Tag
+
+The property tag is simply an empty struct with the name `CahnHilliardModel`.
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../model.hh))</summary>
+
+
+```cpp
+namespace Dumux::Properties::TTag {
+struct CahnHilliardModel {};
+} // end namespace Dumux::Properties::TTag
+```
+
+
+</details>
+
+## 2. The volume variables
+
+The volume variables store the control volume variables, both primary and secondary.
+Let's have a look at the class implementation.
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../model.hh))</summary>
+
+
+We write out a full volume variable class compatible with the Dumux assembly.
+We have to fulfill the same interface as the [`BasicVolumeVariables`](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/common/volumevariables.hh).
+To shorten the code, we could also inherit from `BasicVolumeVariables`. However,
+we want to show the entire interface here as a basis for the implementation of more complex variables.
+Note that in `update` we could, for example, compute some secondary variable that is a
+possibly nonlinear function of the primary variables. That secondary variable could be exposed
+via an interface and then used below in the `CahnHilliardModelLocalResidual` class implementation.
+
+
+```cpp
+namespace Dumux {
+template <class Traits>
+class CahnHilliardModelVolumeVariables
+{
+    using Scalar = typename Traits::PrimaryVariables::value_type;
+    static_assert(Traits::PrimaryVariables::dimension == Traits::ModelTraits::numEq());
+public:
+    //! export the type used for the primary variables
+    using PrimaryVariables = typename Traits::PrimaryVariables;
+    //! export the indices type
+    using Indices = typename Traits::ModelTraits::Indices;
+```
+
+
+**Update variables:** The `update` function stores the local primary variables of the current solution and
+potentially computes secondary variables. Secondary variables can be nonlinear functions
+of the primary variables.
+
+
+```cpp
+    //! Update all quantities for a given control volume
+    template<class ElementSolution, class Problem, class Element, class SubControlVolume>
+    void update(const ElementSolution& elemSol,
+                const Problem& problem,
+                const Element& element,
+                const SubControlVolume& scv)
+    {
+        priVars_ = elemSol[scv.indexInElement()];
+    }
+```
+
+
+**Access functions:** Named and generic functions to access different primary variables.
+The volumevariables are also expected to return an extrusion factor.
+Here we don't extrude our domain and therefore return $1.0$.
+
+```cpp
+    Scalar concentration() const
+    { return priVars_[Indices::concentrationIdx]; }
+
+    Scalar chemicalPotential() const
+    { return priVars_[Indices::chemicalPotentialIdx]; }
+
+    Scalar priVar(const int pvIdx) const
+    { return priVars_[pvIdx]; }
+
+    const PrimaryVariables& priVars() const
+    { return priVars_; }
+
+    Scalar extrusionFactor() const
+    { return 1.0; }
+
+private:
+    PrimaryVariables priVars_;
+};
+} // end namespace Dumux
+```
+
+
+</details>
+
+## 3. The local residual
+
+The local residual assembles the contribution to the residual for
+all degrees of freedom associated with an element.
+See [examples/diffusion/doc/model.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/doc/main.md)
+for a more detailed explanation for control-volume finite element method local residuals.
+Let's have a look at the class implementation.
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../model.hh))</summary>
+
+
+The class `CahnHilliardModelLocalResidual` inherits from a base class set in
+the model properties, depending on the discretization scheme.
+See [examples/diffusion/doc/model.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/doc/main.md)
+for details on the `BaseLocalResidual`.
+
+```cpp
+namespace Dumux {
+template<class TypeTag>
+class CahnHilliardModelLocalResidual
+: public GetPropType<TypeTag, Properties::BaseLocalResidual>
+{
+```
+
+
+**Storage term:** The function `computeStorage` receives the volume variables
+at the previous or current time step and computes the value of the storage terms.
+In this case the mass balance equation is a conservation equation of the concentration and
+the equation for the chemical potential does not have a storage term.
+
+
+```cpp
+    NumEqVector computeStorage(const Problem& problem,
+                               const SubControlVolume& scv,
+                               const VolumeVariables& volVars) const
+    {
+        NumEqVector storage;
+        storage[Indices::massBalanceEqIdx] = volVars.concentration();
+        storage[Indices::chemicalPotentialEqIdx] = 0.0;
+        return storage;
+    }
+```
+
+**Flux term:** The function `computeFlux` computes the fluxes
+over a sub control volume faces, including the integration over
+the area of the face.
+
+```math
+\begin{aligned}
+F_{K,\sigma,0} &= -M \sum_{B \in \mathcal{B}_K} \mu_{h,B} \nabla N_B \cdot\boldsymbol{n} \vert \sigma \vert \\
+F_{K,\sigma,1} &= -\gamma \sum_{B \in \mathcal{B}_K} c_{h,B} \nabla N_B \cdot\boldsymbol{n} \vert \sigma \vert
+\end{aligned}
+````
+
+
+```cpp
+    NumEqVector computeFlux(const Problem& problem,
+                            const Element& element,
+                            const FVElementGeometry& fvGeometry,
+                            const ElementVolumeVariables& elemVolVars,
+                            const SubControlVolumeFace& scvf,
+                            const ElementFluxVariablesCache& elemFluxVarsCache) const
+    {
+        static_assert(DiscretizationMethods::isCVFE<typename GridGeometry::DiscretizationMethod>,
+            "This local residual is hard-coded to control-volume finite element schemes");
+
+        const auto& fluxVarCache = elemFluxVarsCache[scvf];
+        Dune::FieldVector<Scalar, dimWorld> gradConcentration(0.0);
+        Dune::FieldVector<Scalar, dimWorld> gradChemicalPotential(0.0);
+        for (const auto& scv : scvs(fvGeometry))
+        {
+            const auto& volVars = elemVolVars[scv];
+            // v.axpy(a, w) means v <- v + a*w
+            gradConcentration.axpy(
+                volVars.concentration(),
+                fluxVarCache.gradN(scv.indexInElement())
+            );
+            gradChemicalPotential.axpy(
+                volVars.chemicalPotential(),
+                fluxVarCache.gradN(scv.indexInElement())
+            );
+        }
+
+        NumEqVector flux;
+        // Compute the flux with `vtmv` (vector transposed times matrix times vector).
+        // The mobility and surface tension coefficients comes from the `problem` (see Part 2 of the example).
+        flux[Indices::massBalanceEqIdx] = -1.0*vtmv(
+            scvf.unitOuterNormal(), problem.mobility(), gradChemicalPotential
+        )*scvf.area();
+        flux[Indices::chemicalPotentialEqIdx] = -1.0*vtmv(
+            scvf.unitOuterNormal(), problem.surfaceTension(), gradConcentration
+        )*scvf.area();
+        return flux;
+    }
+```
+
+**Source term:** The function `computeSource` computes the sources terms for a sub control volume.
+We implement a model-specific source term for the chemical potential equation before
+deferring further implementation to the problem where we add the derivative of the free
+energy.
+
+
+```cpp
+    NumEqVector computeSource(const Problem& problem,
+                              const Element& element,
+                              const FVElementGeometry& fvGeometry,
+                              const ElementVolumeVariables& elemVolVars,
+                              const SubControlVolume &scv) const
+    {
+        NumEqVector source(0.0);
+        source[Indices::massBalanceEqIdx] = 0.0;
+        source[Indices::chemicalPotentialEqIdx] = elemVolVars[scv].chemicalPotential();
+        // add contributions from problem (e.g. double well potential)
+        source += problem.source(element, fvGeometry, elemVolVars, scv);
+        return source;
+    }
+};
+} // end namespace Dumux
+```
+
+
+</details>
+
+## 4. The model properties/traits
+
+In the `Dumux::Properties` namespace, we specialize properties for
+the created type tag `CahnHilliardModel`.
+
+
+<details open>
+<summary><b>Click to hide/show the file documentation</b> (or inspect the [source code](../model.hh))</summary>
+
+
+```cpp
+namespace Dumux::Properties {
+```
+
+The type of the local residual is the class defined above.
+
+```cpp
+template<class TypeTag>
+struct LocalResidual<TypeTag, TTag::CahnHilliardModel>
+{ using type = CahnHilliardModelLocalResidual<TypeTag>; };
+```
+
+The default scalar type is double.
+We compute with double precision floating point numbers.
+
+```cpp
+template<class TypeTag>
+struct Scalar<TypeTag, TTag::CahnHilliardModel>
+{ using type = double; };
+```
+
+The model traits specify some information about our equation system.
+Here we have two equations. The indices allow to access primary variables
+and equations with a named indices.
+
+```cpp
+template<class TypeTag>
+struct ModelTraits<TypeTag, TTag::CahnHilliardModel>
+{
+    struct type
+    {
+        struct Indices
+        {
+            static constexpr int concentrationIdx = 0;
+            static constexpr int chemicalPotentialIdx = 1;
+
+            static constexpr int massBalanceEqIdx = 0;
+            static constexpr int chemicalPotentialEqIdx = 1;
+        };
+
+        static constexpr int numEq() { return 2; }
+    };
+};
+```
+
+The primary variable vector has entries of type `Scalar` and is
+as large as the number of equations (here 2) but we keep it general.
+
+```cpp
+template<class TypeTag>
+struct PrimaryVariables<TypeTag, TTag::CahnHilliardModel>
+{
+    using type = Dune::FieldVector<
+        GetPropType<TypeTag, Properties::Scalar>,
+        GetPropType<TypeTag, Properties::ModelTraits>::numEq()
+    >;
+};
+```
+
+Finally, the type of the volume variables is the class defined above.
+
+```cpp
+template<class TypeTag>
+struct VolumeVariables<TypeTag, TTag::CahnHilliardModel>
+{
+    struct Traits
+    {
+        using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
+        using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
+    };
+
+    using type = CahnHilliardModelVolumeVariables<Traits>;
+};
+
+} // end namespace Dumux::Properties
+```
+
+
+</details>
+
+
+| [:arrow_left: Back to the main documentation](../README.md) | [:arrow_right: Continue with part 2](main.md) |
+|---|---:|
+
diff --git a/examples/cahn_hilliard/img/animation.gif b/examples/cahn_hilliard/img/animation.gif
new file mode 100644
index 0000000000000000000000000000000000000000..6e266f5f8f146c7780dea6f6c1f4ddb950b49d46
Binary files /dev/null and b/examples/cahn_hilliard/img/animation.gif differ
diff --git a/examples/cahn_hilliard/main.cc b/examples/cahn_hilliard/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b91a6d9acbcb8e692f655330baead3f2f60f540e
--- /dev/null
+++ b/examples/cahn_hilliard/main.cc
@@ -0,0 +1,336 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 3 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+
+// # Cahn-Hilliard equation main program
+//
+// The file [`main.cc`](main.cc) contains the problem class `CahnHilliardTestProblem`,
+// properties and traits specific to the test case as well as the `main` function.
+// The setup consists of four steps:
+// 1. Define the problem setting boundary conditions and the diffusion coefficient
+// 2. Configure the property system reusing the model defined in Part 1
+// 3. Define a function for setting the random initial condition
+// 4. The main program defining all steps of the program
+//
+// __Table of contents__
+//
+// [TOC]
+//
+// We start in `main.cc` with the necessary header includes:
+// [[details]] includes
+#include <config.h>
+#include <type_traits>
+#include <random>
+
+#include <dumux/common/initialize.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/numeqvector.hh>
+#include <dumux/common/boundarytypes.hh>
+#include <dumux/common/fvproblem.hh>
+
+#include <dumux/discretization/box.hh>
+#include <dumux/linear/linearsolvertraits.hh>
+#include <dumux/linear/linearalgebratraits.hh>
+#include <dumux/linear/istlsolvers.hh>
+#include <dumux/nonlinear/newtonsolver.hh>
+#include <dumux/assembly/fvassembler.hh>
+
+#include <dune/grid/yaspgrid.hh>
+#include <dumux/io/vtkoutputmodule.hh>
+#include <dumux/io/grid/gridmanager_yasp.hh>
+
+#include "model.hh"
+// [[/details]]
+
+//
+// ## 1. The problem class
+//
+// The problem class implements boundary conditions and the source term.
+// It also provides an interface that is used by the local residual (see Part 1) to obtain
+// the mobility and surface tension. The values are read from the parameter configuration tree.
+// [[content]]
+namespace Dumux {
+template<class TypeTag>
+class CahnHilliardTestProblem : public FVProblem<TypeTag>
+{
+    // [[details]] boilerplate code
+    using ParentType = FVProblem<TypeTag>;
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using FVElementGeometry = typename GridGeometry::LocalView;
+    using SubControlVolume = typename GridGeometry::SubControlVolume;
+    using GridView = typename GetPropType<TypeTag, Properties::GridGeometry>::GridView;
+    using Element = typename GridView::template Codim<0>::Entity;
+    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
+
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
+    using NumEqVector = Dumux::NumEqVector<PrimaryVariables>;
+    using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
+    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
+    // [[/details]]
+    // In the constructor, we read the parameter constants from the
+    // parameter tree (which is initialized with the content of `params.input`).
+public:
+    CahnHilliardTestProblem(std::shared_ptr<const GridGeometry> gridGeometry)
+    : ParentType(gridGeometry)
+    {
+        mobility_ = getParam<Scalar>("Problem.Mobility");
+        surfaceTension_ = getParam<Scalar>("Problem.SurfaceTension");
+        energyScale_ = getParam<Scalar>("Problem.EnergyScale");
+    }
+
+    // In the `source` function, we implement the derivative of the free energy.
+    // This demonstrates how parts of the local residual can be split into model specific
+    // parts and parts that might change from scenario to scenario.
+    template<class ElementVolumeVariables>
+    NumEqVector source(const Element &element,
+                       const FVElementGeometry& fvGeometry,
+                       const ElementVolumeVariables& elemVolVars,
+                       const SubControlVolume &scv) const
+    {
+        NumEqVector values(0.0);
+        const auto& c = elemVolVars[scv].concentration();
+        values[Indices::chemicalPotentialEqIdx] = -energyScale_*2.0*c*(2.0*c*c - 3*c + 1);
+        return values;
+    }
+
+    // For the boundary we choose boundary flux (or Neumann) conditions for all equations and on
+    // every part of the boundary, specifying zero flux everywhere for both equations.
+    // [[codeblock]]
+    BoundaryTypes boundaryTypesAtPos(const GlobalPosition& globalPos) const
+    {
+        BoundaryTypes values;
+        values.setAllNeumann();
+        return values;
+    }
+
+    NumEqVector neumannAtPos(const GlobalPosition& globalPos) const
+    { return { 0.0, 0.0 }; }
+    // [[/codeblock]]
+
+    // The parameters interfaces are used in the local residual (see Part 1).
+    // We can name this interface however we want as long as we adapt the calling site
+    // in the `LocalResidual` class in `model.hh`.
+    // [[codeblock]]
+    Scalar mobility() const
+    { return mobility_; }
+
+    Scalar surfaceTension() const
+    { return surfaceTension_; }
+
+private:
+    Scalar mobility_;
+    Scalar surfaceTension_;
+    Scalar energyScale_;
+};
+} // end namespace Dumux
+// [[/codeblock]]
+// [[/content]]
+
+//
+// ## 2. Property tag and specializations
+//
+// We create a new tag `DiffusionTest` that inherits all properties
+// specialized for the tag `DiffusionModel` (we created this in Part 1)
+// and the tag `BoxModel` which provides types relevant for the spatial
+// discretization scheme (see [dumux/discretization/box.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/discretization/box.hh)).
+//
+// [[content]]
+namespace Dumux::Properties::TTag {
+struct CahnHilliardTest
+{
+    using InheritsFrom = std::tuple<CahnHilliardModel, BoxModel>;
+
+    using Grid = Dune::YaspGrid<2>;
+
+    template<class TypeTag>
+    using Problem = CahnHilliardTestProblem<TypeTag>;
+
+    using EnableGridGeometryCache = std::true_type;
+    using EnableGridVolumeVariablesCache = std::true_type;
+    using EnableGridFluxVariablesCache = std::true_type;
+};
+} // end namespace Dumux::Properties
+// [[/content]]
+//
+// ## 3. Creating the initial solution
+//
+// To initialize with a random field in parallel, where each processor
+// creates its own random number sequence, we need to communicate the
+// resulting values on the processor border and overlap.
+// See [Diffusion equation example](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/docs/main.md).
+// for details. Here in addition, we need to provide a custom scatter operation
+// that handles vector types. We only need to communicate the first entry (concentration).
+//
+// [[content]]
+// [[codeblock]]
+// functor for data communication with MPI
+struct MinScatter
+{
+    template<class A, class B>
+    static void apply(A& a, const B& b)
+    { a[0] = std::min(a[0], b[0]); }
+};
+
+// create the random initial solution
+template<class SolutionVector, class GridGeometry>
+SolutionVector createInitialSolution(const GridGeometry& gg)
+{
+    SolutionVector sol(gg.numDofs());
+
+    // Generate random number and add processor offset
+    // For sequential runs `rank` always returns `0`.
+    std::mt19937 gen(0); // seed is 0 for deterministic results
+    std::uniform_real_distribution<> dis(0.0, 1.0);
+    for (int n = 0; n < sol.size(); ++n)
+    {
+        sol[n][0] = 0.42 + 0.02*(0.5-dis(gen)) + gg.gridView().comm().rank();
+        sol[n][1] = 0.0;
+    }
+
+    // We take the value of the processor with the minimum rank
+    // and subtract the rank offset
+    if (gg.gridView().comm().size() > 1)
+    {
+        Dumux::VectorCommDataHandle<
+            typename GridGeometry::VertexMapper,
+            SolutionVector,
+            GridGeometry::GridView::dimension,
+            MinScatter
+        > minHandle(gg.vertexMapper(), sol);
+        gg.gridView().communicate(minHandle, Dune::All_All_Interface, Dune::ForwardCommunication);
+
+        // Remove processor offset
+        for (int n = 0; n < sol.size(); ++n)
+            sol[n][0] -= std::floor(sol[n][0]);
+    }
+    return sol;
+}
+// [[/codeblock]]
+// [[/content]]
+//
+// ## 4. The main program
+//
+// The `main` function sets up the simulation framework, initializes runtime parameters,
+// creates the grid and storage vectors
+// for the variables, primary and secondary. It specifies and constructs and assembler, which
+// assembles the discretized residual and system matrix (Jacobian of the model residual), as well as
+// a linear solver. A Newton method is used to solve the nonlinear equations where in each Newton iteration
+// the Jacobian and the residual needs to be reassembled and the resulting linear system is solved.
+// The time loop controls the time stepping. Here, we let the Newton solver suggest an adaption of
+// the time step size based on the convergence history of the nonlinear solver.
+//
+// [[content]]
+int main(int argc, char** argv)
+{
+    using namespace Dumux;
+
+    // We initialize MPI and/or multithreading backend. When not running
+    // in parallel the MPI setup is skipped.
+    Dumux::initialize(argc, argv);
+
+    // Then we initialize parameter tree.
+    Parameters::init(argc, argv);
+
+    // We create an alias for the type tag for this problem
+    // and extract type information through properties.
+    using TypeTag = Properties::TTag::CahnHilliardTest;
+
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using Grid = GetPropType<TypeTag, Properties::Grid>;
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
+    using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
+    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+
+    // We initialize the grid, grid geometry, problem, solution vector, and grid variables.
+    GridManager<Grid> gridManager;
+    gridManager.init();
+
+    auto gridGeometry = std::make_shared<GridGeometry>(gridManager.grid().leafGridView());
+    auto problem = std::make_shared<Problem>(gridGeometry);
+    auto sol = createInitialSolution<SolutionVector>(*gridGeometry);
+    auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
+    gridVariables->init(sol);
+
+    // We initialize the VTK output module and write out the initial concentration and chemical potential
+    VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name());
+    vtkWriter.addVolumeVariable([](const auto& vv){ return vv.concentration(); }, "c");
+    vtkWriter.addVolumeVariable([](const auto& vv){ return vv.chemicalPotential(); }, "mu");
+    vtkWriter.write(0.0);
+
+    // We instantiate time loop using start and end time as well as
+    // the time step size from the parameter tree (`params.input`)
+    auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>(
+        getParam<Scalar>("TimeLoop.TStart", 0.0),
+        getParam<Scalar>("TimeLoop.InitialTimeStepSize"),
+        getParam<Scalar>("TimeLoop.TEnd")
+    );
+
+    // We set the maximum time step size allowed in the adaptive time stepping scheme.
+    timeLoop->setMaxTimeStepSize(getParam<Scalar>("TimeLoop.MaxTimeStepSize"));
+
+    // Next, we choose the type of assembler, linear solver and PDE solver
+    // and construct instances of these classes.
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    using LinearSolver = SSORBiCGSTABIstlSolver<LinearSolverTraits<GridGeometry>, LinearAlgebraTraitsFromAssembler<Assembler>>;
+    using Solver = Dumux::NewtonSolver<Assembler, LinearSolver>;
+
+    auto oldSol = sol;
+    auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, oldSol);
+    auto linearSolver = std::make_shared<LinearSolver>(gridGeometry->gridView(), gridGeometry->dofMapper());
+    Solver solver(assembler, linearSolver);
+
+    // The time loop is where most of the actual computations happen.
+    // We assemble and solve the linear system of equations, update the solution,
+    // write the solution to a VTK file and continue until the we reach the
+    // final simulation time.
+    //
+    // [[codeblock]]
+    timeLoop->start(); do
+    {
+        // Assemble & solve
+        // Passing the time loop enables the solver to repeat the time step
+        // with a reduced time step size if the Newton solver does not converge.
+        solver.solve(sol, *timeLoop);
+
+        // make the new solution the old solution
+        oldSol = sol;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        // write VTK output (concentration field and chemical potential)
+        vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by the Newton solver
+        timeLoop->setTimeStepSize(solver.suggestTimeStepSize(timeLoop->timeStepSize()));
+
+    } while (!timeLoop->finished());
+
+    // print the final report
+    timeLoop->finalize(gridGeometry->gridView().comm());
+    return 0;
+}
+// [[/codeblock]]
+// [[/content]]
diff --git a/examples/cahn_hilliard/model.hh b/examples/cahn_hilliard/model.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f77c3d4f3f740e2c5cc6f146e7be61a3f3b1175f
--- /dev/null
+++ b/examples/cahn_hilliard/model.hh
@@ -0,0 +1,338 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 3 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+
+#ifndef DUMUX_EXAMPLES_CAHN_HILLIARD_MODEL_HH
+#define DUMUX_EXAMPLES_CAHN_HILLIARD_MODEL_HH
+
+// # Cahn-Hilliard equation model definition
+//
+// In the file `model.hh`, we define the model equations and
+// set all default model properties. The setup consist of four steps:
+// 1. Create a model type tag (used to specialize properties)
+// 2. Define the volume variables class computing and storing variables for a control volume
+// 3. Define the local residual class implementing the discrete equation
+// 4. Specialize important properties of the model such that Dumux knows how to assemble the system matrix
+//
+// We implement the classes
+//
+// * `CahnHilliardModel` (step 1),
+// * `CahnHilliardModelVolumeVariables` (step 2) and
+// * `CahnHilliardModelLocalResidual` (step 3).
+//
+// __Table of contents__
+//
+// [TOC]
+//
+// We start in `model.hh` with the necessary header includes:
+// [[details]] includes
+#include <dumux/common/math.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/numeqvector.hh>
+// [[/details]]
+//
+// ## 1. Property Tag
+//
+// The property tag is simply an empty struct with the name `CahnHilliardModel`.
+//
+// [[content]]
+// [[codeblock]]
+namespace Dumux::Properties::TTag {
+struct CahnHilliardModel {};
+} // end namespace Dumux::Properties::TTag
+// [[/codeblock]]
+// [[/content]]
+//
+// ## 2. The volume variables
+//
+// The volume variables store the control volume variables, both primary and secondary.
+// Let's have a look at the class implementation.
+//
+// [[content]]
+//
+// We write out a full volume variable class compatible with the Dumux assembly.
+// We have to fulfill the same interface as the [`BasicVolumeVariables`](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/common/volumevariables.hh).
+// To shorten the code, we could also inherit from `BasicVolumeVariables`. However,
+// we want to show the entire interface here as a basis for the implementation of more complex variables.
+// Note that in `update` we could, for example, compute some secondary variable that is a
+// possibly nonlinear function of the primary variables. That secondary variable could be exposed
+// via an interface and then used below in the `CahnHilliardModelLocalResidual` class implementation.
+//
+// [[codeblock]]
+namespace Dumux {
+template <class Traits>
+class CahnHilliardModelVolumeVariables
+{
+    using Scalar = typename Traits::PrimaryVariables::value_type;
+    static_assert(Traits::PrimaryVariables::dimension == Traits::ModelTraits::numEq());
+public:
+    //! export the type used for the primary variables
+    using PrimaryVariables = typename Traits::PrimaryVariables;
+    //! export the indices type
+    using Indices = typename Traits::ModelTraits::Indices;
+// [[/codeblock]]
+    //
+    // **Update variables:** The `update` function stores the local primary variables of the current solution and
+    // potentially computes secondary variables. Secondary variables can be nonlinear functions
+    // of the primary variables.
+    //
+    // [[codeblock]]
+    //! Update all quantities for a given control volume
+    template<class ElementSolution, class Problem, class Element, class SubControlVolume>
+    void update(const ElementSolution& elemSol,
+                const Problem& problem,
+                const Element& element,
+                const SubControlVolume& scv)
+    {
+        priVars_ = elemSol[scv.indexInElement()];
+    }
+    // [[/codeblock]]
+    //
+    // **Access functions:** Named and generic functions to access different primary variables.
+    // The volumevariables are also expected to return an extrusion factor.
+    // Here we don't extrude our domain and therefore return $1.0$.
+    // [[codeblock]]
+    Scalar concentration() const
+    { return priVars_[Indices::concentrationIdx]; }
+
+    Scalar chemicalPotential() const
+    { return priVars_[Indices::chemicalPotentialIdx]; }
+
+    Scalar priVar(const int pvIdx) const
+    { return priVars_[pvIdx]; }
+
+    const PrimaryVariables& priVars() const
+    { return priVars_; }
+
+    Scalar extrusionFactor() const
+    { return 1.0; }
+
+private:
+    PrimaryVariables priVars_;
+};
+} // end namespace Dumux
+// [[/codeblock]]
+// [[/content]]
+//
+// ## 3. The local residual
+//
+// The local residual assembles the contribution to the residual for
+// all degrees of freedom associated with an element.
+// See [examples/diffusion/doc/model.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/doc/main.md)
+// for a more detailed explanation for control-volume finite element method local residuals.
+// Let's have a look at the class implementation.
+//
+// [[content]]
+//
+// The class `CahnHilliardModelLocalResidual` inherits from a base class set in
+// the model properties, depending on the discretization scheme.
+// See [examples/diffusion/doc/model.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/examples/diffusion/doc/main.md)
+// for details on the `BaseLocalResidual`.
+namespace Dumux {
+template<class TypeTag>
+class CahnHilliardModelLocalResidual
+: public GetPropType<TypeTag, Properties::BaseLocalResidual>
+{
+    // [[exclude]]
+    // the base local residual is selected depending on the chosen discretization scheme
+    using ParentType = GetPropType<TypeTag, Properties::BaseLocalResidual>;
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
+    using NumEqVector = Dumux::NumEqVector<GetPropType<TypeTag, Properties::PrimaryVariables>>;
+
+    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+    using VolumeVariables = typename GridVariables::GridVolumeVariables::VolumeVariables;
+    using ElementVolumeVariables = typename GridVariables::GridVolumeVariables::LocalView;
+    using ElementFluxVariablesCache = typename GridVariables::GridFluxVariablesCache::LocalView;
+
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using FVElementGeometry = typename GridGeometry::LocalView;
+    using SubControlVolume = typename GridGeometry::SubControlVolume;
+    using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
+    using GridView = typename GridGeometry::GridView;
+    using Element = typename GridView::template Codim<0>::Entity;
+
+    using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
+    using Indices = typename ModelTraits::Indices;
+    static constexpr int dimWorld = GridView::dimensionworld;
+public:
+    using ParentType::ParentType;
+    // [[/exclude]]
+    //
+    // **Storage term:** The function `computeStorage` receives the volume variables
+    // at the previous or current time step and computes the value of the storage terms.
+    // In this case the mass balance equation is a conservation equation of the concentration and
+    // the equation for the chemical potential does not have a storage term.
+    //
+    // [[codeblock]]
+    NumEqVector computeStorage(const Problem& problem,
+                               const SubControlVolume& scv,
+                               const VolumeVariables& volVars) const
+    {
+        NumEqVector storage;
+        storage[Indices::massBalanceEqIdx] = volVars.concentration();
+        storage[Indices::chemicalPotentialEqIdx] = 0.0;
+        return storage;
+    }
+    // [[/codeblock]]
+
+    // **Flux term:** The function `computeFlux` computes the fluxes
+    // over a sub control volume faces, including the integration over
+    // the area of the face.
+    //
+    // ```math
+    // \begin{aligned}
+    // F_{K,\sigma,0} &= -M \sum_{B \in \mathcal{B}_K} \mu_{h,B} \nabla N_B \cdot\boldsymbol{n} \vert \sigma \vert \\
+    // F_{K,\sigma,1} &= -\gamma \sum_{B \in \mathcal{B}_K} c_{h,B} \nabla N_B \cdot\boldsymbol{n} \vert \sigma \vert
+    // \end{aligned}
+    // ````
+    //
+    // [[codeblock]]
+    NumEqVector computeFlux(const Problem& problem,
+                            const Element& element,
+                            const FVElementGeometry& fvGeometry,
+                            const ElementVolumeVariables& elemVolVars,
+                            const SubControlVolumeFace& scvf,
+                            const ElementFluxVariablesCache& elemFluxVarsCache) const
+    {
+        static_assert(DiscretizationMethods::isCVFE<typename GridGeometry::DiscretizationMethod>,
+            "This local residual is hard-coded to control-volume finite element schemes");
+
+        const auto& fluxVarCache = elemFluxVarsCache[scvf];
+        Dune::FieldVector<Scalar, dimWorld> gradConcentration(0.0);
+        Dune::FieldVector<Scalar, dimWorld> gradChemicalPotential(0.0);
+        for (const auto& scv : scvs(fvGeometry))
+        {
+            const auto& volVars = elemVolVars[scv];
+            // v.axpy(a, w) means v <- v + a*w
+            gradConcentration.axpy(
+                volVars.concentration(),
+                fluxVarCache.gradN(scv.indexInElement())
+            );
+            gradChemicalPotential.axpy(
+                volVars.chemicalPotential(),
+                fluxVarCache.gradN(scv.indexInElement())
+            );
+        }
+
+        NumEqVector flux;
+        // Compute the flux with `vtmv` (vector transposed times matrix times vector).
+        // The mobility and surface tension coefficients comes from the `problem` (see Part 2 of the example).
+        flux[Indices::massBalanceEqIdx] = -1.0*vtmv(
+            scvf.unitOuterNormal(), problem.mobility(), gradChemicalPotential
+        )*scvf.area();
+        flux[Indices::chemicalPotentialEqIdx] = -1.0*vtmv(
+            scvf.unitOuterNormal(), problem.surfaceTension(), gradConcentration
+        )*scvf.area();
+        return flux;
+    }
+    // [[/codeblock]]
+
+    // **Source term:** The function `computeSource` computes the sources terms for a sub control volume.
+    // We implement a model-specific source term for the chemical potential equation before
+    // deferring further implementation to the problem where we add the derivative of the free
+    // energy.
+    //
+    // [[codeblock]]
+    NumEqVector computeSource(const Problem& problem,
+                              const Element& element,
+                              const FVElementGeometry& fvGeometry,
+                              const ElementVolumeVariables& elemVolVars,
+                              const SubControlVolume &scv) const
+    {
+        NumEqVector source(0.0);
+        source[Indices::massBalanceEqIdx] = 0.0;
+        source[Indices::chemicalPotentialEqIdx] = elemVolVars[scv].chemicalPotential();
+        // add contributions from problem (e.g. double well potential)
+        source += problem.source(element, fvGeometry, elemVolVars, scv);
+        return source;
+    }
+};
+} // end namespace Dumux
+// [[/codeblock]]
+// [[/content]]
+//
+// ## 4. The model properties/traits
+//
+// In the `Dumux::Properties` namespace, we specialize properties for
+// the created type tag `CahnHilliardModel`.
+//
+// [[content]]
+namespace Dumux::Properties {
+
+// The type of the local residual is the class defined above.
+template<class TypeTag>
+struct LocalResidual<TypeTag, TTag::CahnHilliardModel>
+{ using type = CahnHilliardModelLocalResidual<TypeTag>; };
+
+// The default scalar type is double.
+// We compute with double precision floating point numbers.
+template<class TypeTag>
+struct Scalar<TypeTag, TTag::CahnHilliardModel>
+{ using type = double; };
+
+// The model traits specify some information about our equation system.
+// Here we have two equations. The indices allow to access primary variables
+// and equations with a named indices.
+template<class TypeTag>
+struct ModelTraits<TypeTag, TTag::CahnHilliardModel>
+{
+    struct type
+    {
+        struct Indices
+        {
+            static constexpr int concentrationIdx = 0;
+            static constexpr int chemicalPotentialIdx = 1;
+
+            static constexpr int massBalanceEqIdx = 0;
+            static constexpr int chemicalPotentialEqIdx = 1;
+        };
+
+        static constexpr int numEq() { return 2; }
+    };
+};
+
+// The primary variable vector has entries of type `Scalar` and is
+// as large as the number of equations (here 2) but we keep it general.
+template<class TypeTag>
+struct PrimaryVariables<TypeTag, TTag::CahnHilliardModel>
+{
+    using type = Dune::FieldVector<
+        GetPropType<TypeTag, Properties::Scalar>,
+        GetPropType<TypeTag, Properties::ModelTraits>::numEq()
+    >;
+};
+
+// Finally, the type of the volume variables is the class defined above.
+template<class TypeTag>
+struct VolumeVariables<TypeTag, TTag::CahnHilliardModel>
+{
+    struct Traits
+    {
+        using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
+        using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
+    };
+
+    using type = CahnHilliardModelVolumeVariables<Traits>;
+};
+
+} // end namespace Dumux::Properties
+// [[/content]]
+// [[exclude]]
+#endif
+// [[/exclude]]
diff --git a/examples/cahn_hilliard/params.input b/examples/cahn_hilliard/params.input
new file mode 100644
index 0000000000000000000000000000000000000000..f9d41a960d4dd43dd177449a3ffdba6ea82425c4
--- /dev/null
+++ b/examples/cahn_hilliard/params.input
@@ -0,0 +1,19 @@
+[TimeLoop]
+TEnd = 1.0
+InitialTimeStepSize = 0.0025
+MaxTimeStepSize = 0.01
+
+[Grid]
+LowerLeft = 0 0
+UpperRight = 1 1
+Cells = 100 100
+Overlap = 2
+
+[Problem]
+Name = cahn_hilliard
+Mobility = 0.0001
+SurfaceTension = 0.01
+EnergyScale = 100
+
+[Newton]
+EnablePartialReassembly = true
diff --git a/examples/diffusion/doc/main.md b/examples/diffusion/doc/main.md
index 28d3bd539ab5ae4faf80e587e086cb8d4ef1a25c..28791805adf788e9b36959401d4423087b806ac6 100644
--- a/examples/diffusion/doc/main.md
+++ b/examples/diffusion/doc/main.md
@@ -248,7 +248,7 @@ SolutionVector createInitialSolution(const GridGeometry& gg)
     for (int n = 0; n < sol.size(); ++n)
         sol[n] = dis(gen) + rank;
 
-    // We, take the value of the processor with the minimum rank
+    // We take the value of the processor with the minimum rank
     // and subtract the rank offset
     if (gg.gridView().comm().size() > 1)
     {
@@ -341,7 +341,7 @@ the problem for the boundary conditions, a solution vector and a grid variables
     gridVariables->init(sol);
 ```
 
-Ww initialize the VTK output module and write out the initial concentration field
+We initialize the VTK output module and write out the initial concentration field
 
 ```cpp
     VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name());
diff --git a/examples/diffusion/main.cc b/examples/diffusion/main.cc
index fb80e86507353b649afc9a898c5e105636503af5..a3585e7eda6afad123933362147c9aeecd0bbbda 100644
--- a/examples/diffusion/main.cc
+++ b/examples/diffusion/main.cc
@@ -204,7 +204,7 @@ SolutionVector createInitialSolution(const GridGeometry& gg)
     for (int n = 0; n < sol.size(); ++n)
         sol[n] = dis(gen) + rank;
 
-    // We, take the value of the processor with the minimum rank
+    // We take the value of the processor with the minimum rank
     // and subtract the rank offset
     if (gg.gridView().comm().size() > 1)
     {
@@ -274,7 +274,7 @@ int main(int argc, char** argv)
     auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
     gridVariables->init(sol);
 
-    // Ww initialize the VTK output module and write out the initial concentration field
+    // We initialize the VTK output module and write out the initial concentration field
     VtkOutputModule<GridVariables, SolutionVector> vtkWriter(*gridVariables, sol, problem->name());
     vtkWriter.addVolumeVariable([](const auto& vv){ return vv.priVar(0); }, "c");
     vtkWriter.write(0.0);
diff --git a/test/references/example_cahn_hilliard-reference.vtu b/test/references/example_cahn_hilliard-reference.vtu
new file mode 100644
index 0000000000000000000000000000000000000000..09646223e7ad6c42a05c1f58c59541c0eb1bd1bd
--- /dev/null
+++ b/test/references/example_cahn_hilliard-reference.vtu
@@ -0,0 +1,143 @@
+<?xml version="1.0"?>
+<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">
+  <UnstructuredGrid>
+    <Piece NumberOfCells="100" NumberOfPoints="121">
+      <PointData Scalars="c">
+        <DataArray type="Float32" Name="c" NumberOfComponents="1" format="ascii">
+          0.0147483 0.0153922 0.0152169 0.0159215 0.0211903 0.0219842 0.0574734 0.059312 0.243869 0.249797 0.780021 0.785981
+          0.933771 0.937786 0.919201 0.930348 0.727812 0.794766 0.217154 0.371188 0.089294 0.205316 0.0165708 0.0174294
+          0.0241264 0.0638759 0.264274 0.799598 0.947169 0.952779 0.895596 0.777857 0.689978 0.0188589 0.0198609 0.0270257
+          0.0679906 0.274159 0.808361 0.955311 0.970942 0.952698 0.923767 0.908282 0.0236373 0.0244423 0.0307829 0.0674349
+          0.253451 0.784383 0.949036 0.976182 0.970998 0.960571 0.955706 0.0420799 0.0405039 0.0407857 0.063462 0.187209
+          0.640986 0.887371 0.944205 0.948217 0.940673 0.936661 0.140059 0.120251 0.08502 0.0715591 0.116467 0.284734
+          0.626543 0.764201 0.781002 0.767473 0.75901 0.57634 0.471128 0.260339 0.131959 0.0887285 0.112697 0.177008
+          0.230102 0.238261 0.225351 0.218237 0.913277 0.880901 0.73408 0.319931 0.1164 0.0626875 0.0578299 0.059922
+          0.0573087 0.0520993 0.0496347 0.995737 0.983019 0.91484 0.650198 0.178748 0.0581001 0.0342137 0.027712 0.0233939
+          0.0199908 0.0186564 1.00917 1.00078 0.952561 0.748489 0.215301 0.06028 0.0307777 0.0230179 0.0186793 0.0156897
+          0.0145771
+        </DataArray>
+        <DataArray type="Float32" Name="mu" NumberOfComponents="1" format="ascii">
+          2.70616 2.62202 2.78879 2.71354 2.34932 2.46783 1.82308 1.98541 0.912757 1.12665 -0.645811 -0.389002
+          -2.94258 -2.62547 -5.9443 -5.52026 -9.56572 -8.97809 -12.1828 -12.2064 -12.9292 -12.8866 3.01891 2.96958
+          2.80417 2.45808 1.7679 0.378813 -1.70733 -4.34003 -7.36216 -10.3029 -11.8652 3.34487 3.33489 3.29487
+          3.17847 2.80737 1.63606 -0.278211 -2.63278 -5.13046 -7.2605 -8.15371 3.68841 3.7232 3.82718 3.98948
+          4.08821 3.32235 1.53081 -0.675997 -2.84224 -4.49376 -5.12372 3.9604 4.03591 4.26374 4.65125 5.15866
+          5.25912 3.48158 1.27611 -0.847849 -2.39324 -2.96585 4.08588 4.19506 4.50428 4.98384 5.58717 6.07524
+          5.20498 2.9048 0.717505 -0.890181 -1.49583 4.07639 4.19553 4.54804 4.99335 5.43628 5.60167 5.04849
+          3.62242 1.85036 0.491861 -0.00883526 4.19789 4.27215 4.48041 4.81194 5.0771 5.07193 4.60785 3.6696
+          2.53143 1.62376 1.28207 4.26478 4.30765 4.42553 4.58578 4.78349 4.73602 4.35412 3.67582 2.88825
+          2.26172 2.02395 4.28205 4.31461 4.3997 4.51565 4.67059 4.62439 4.27705 3.68104 3.00106 2.46303
+          2.25887
+        </DataArray>
+      </PointData>
+      <CellData Scalars="process rank">
+        <DataArray type="Float32" Name="process rank" NumberOfComponents="1" format="ascii">
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0
+        </DataArray>
+      </CellData>
+      <Points>
+        <DataArray type="Float32" Name="Coordinates" NumberOfComponents="3" format="ascii">
+          0 0 0 0.1 0 0 0 0.1 0 0.1 0.1 0
+          0.2 0 0 0.2 0.1 0 0.3 0 0 0.3 0.1 0
+          0.4 0 0 0.4 0.1 0 0.5 0 0 0.5 0.1 0
+          0.6 0 0 0.6 0.1 0 0.7 0 0 0.7 0.1 0
+          0.8 0 0 0.8 0.1 0 0.9 0 0 0.9 0.1 0
+          1 0 0 1 0.1 0 0 0.2 0 0.1 0.2 0
+          0.2 0.2 0 0.3 0.2 0 0.4 0.2 0 0.5 0.2 0
+          0.6 0.2 0 0.7 0.2 0 0.8 0.2 0 0.9 0.2 0
+          1 0.2 0 0 0.3 0 0.1 0.3 0 0.2 0.3 0
+          0.3 0.3 0 0.4 0.3 0 0.5 0.3 0 0.6 0.3 0
+          0.7 0.3 0 0.8 0.3 0 0.9 0.3 0 1 0.3 0
+          0 0.4 0 0.1 0.4 0 0.2 0.4 0 0.3 0.4 0
+          0.4 0.4 0 0.5 0.4 0 0.6 0.4 0 0.7 0.4 0
+          0.8 0.4 0 0.9 0.4 0 1 0.4 0 0 0.5 0
+          0.1 0.5 0 0.2 0.5 0 0.3 0.5 0 0.4 0.5 0
+          0.5 0.5 0 0.6 0.5 0 0.7 0.5 0 0.8 0.5 0
+          0.9 0.5 0 1 0.5 0 0 0.6 0 0.1 0.6 0
+          0.2 0.6 0 0.3 0.6 0 0.4 0.6 0 0.5 0.6 0
+          0.6 0.6 0 0.7 0.6 0 0.8 0.6 0 0.9 0.6 0
+          1 0.6 0 0 0.7 0 0.1 0.7 0 0.2 0.7 0
+          0.3 0.7 0 0.4 0.7 0 0.5 0.7 0 0.6 0.7 0
+          0.7 0.7 0 0.8 0.7 0 0.9 0.7 0 1 0.7 0
+          0 0.8 0 0.1 0.8 0 0.2 0.8 0 0.3 0.8 0
+          0.4 0.8 0 0.5 0.8 0 0.6 0.8 0 0.7 0.8 0
+          0.8 0.8 0 0.9 0.8 0 1 0.8 0 0 0.9 0
+          0.1 0.9 0 0.2 0.9 0 0.3 0.9 0 0.4 0.9 0
+          0.5 0.9 0 0.6 0.9 0 0.7 0.9 0 0.8 0.9 0
+          0.9 0.9 0 1 0.9 0 0 1 0 0.1 1 0
+          0.2 1 0 0.3 1 0 0.4 1 0 0.5 1 0
+          0.6 1 0 0.7 1 0 0.8 1 0 0.9 1 0
+          1 1 0
+        </DataArray>
+      </Points>
+      <Cells>
+        <DataArray type="Int32" Name="connectivity" NumberOfComponents="1" format="ascii">
+          0 1 3 2 1 4 5 3 4 6 7 5
+          6 8 9 7 8 10 11 9 10 12 13 11
+          12 14 15 13 14 16 17 15 16 18 19 17
+          18 20 21 19 2 3 23 22 3 5 24 23
+          5 7 25 24 7 9 26 25 9 11 27 26
+          11 13 28 27 13 15 29 28 15 17 30 29
+          17 19 31 30 19 21 32 31 22 23 34 33
+          23 24 35 34 24 25 36 35 25 26 37 36
+          26 27 38 37 27 28 39 38 28 29 40 39
+          29 30 41 40 30 31 42 41 31 32 43 42
+          33 34 45 44 34 35 46 45 35 36 47 46
+          36 37 48 47 37 38 49 48 38 39 50 49
+          39 40 51 50 40 41 52 51 41 42 53 52
+          42 43 54 53 44 45 56 55 45 46 57 56
+          46 47 58 57 47 48 59 58 48 49 60 59
+          49 50 61 60 50 51 62 61 51 52 63 62
+          52 53 64 63 53 54 65 64 55 56 67 66
+          56 57 68 67 57 58 69 68 58 59 70 69
+          59 60 71 70 60 61 72 71 61 62 73 72
+          62 63 74 73 63 64 75 74 64 65 76 75
+          66 67 78 77 67 68 79 78 68 69 80 79
+          69 70 81 80 70 71 82 81 71 72 83 82
+          72 73 84 83 73 74 85 84 74 75 86 85
+          75 76 87 86 77 78 89 88 78 79 90 89
+          79 80 91 90 80 81 92 91 81 82 93 92
+          82 83 94 93 83 84 95 94 84 85 96 95
+          85 86 97 96 86 87 98 97 88 89 100 99
+          89 90 101 100 90 91 102 101 91 92 103 102
+          92 93 104 103 93 94 105 104 94 95 106 105
+          95 96 107 106 96 97 108 107 97 98 109 108
+          99 100 111 110 100 101 112 111 101 102 113 112
+          102 103 114 113 103 104 115 114 104 105 116 115
+          105 106 117 116 106 107 118 117 107 108 119 118
+          108 109 120 119
+        </DataArray>
+        <DataArray type="Int32" Name="offsets" NumberOfComponents="1" format="ascii">
+          4 8 12 16 20 24 28 32 36 40 44 48
+          52 56 60 64 68 72 76 80 84 88 92 96
+          100 104 108 112 116 120 124 128 132 136 140 144
+          148 152 156 160 164 168 172 176 180 184 188 192
+          196 200 204 208 212 216 220 224 228 232 236 240
+          244 248 252 256 260 264 268 272 276 280 284 288
+          292 296 300 304 308 312 316 320 324 328 332 336
+          340 344 348 352 356 360 364 368 372 376 380 384
+          388 392 396 400
+        </DataArray>
+        <DataArray type="UInt8" Name="types" NumberOfComponents="1" format="ascii">
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9
+        </DataArray>
+      </Cells>
+    </Piece>
+  </UnstructuredGrid>
+</VTKFile>
diff --git a/test/references/example_cahn_hilliard_parallel_p0-reference.vtu b/test/references/example_cahn_hilliard_parallel_p0-reference.vtu
new file mode 100644
index 0000000000000000000000000000000000000000..33055a97eeb03d8d6140ce53d1c5286421968576
--- /dev/null
+++ b/test/references/example_cahn_hilliard_parallel_p0-reference.vtu
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">
+  <UnstructuredGrid>
+    <Piece NumberOfCells="50" NumberOfPoints="66">
+      <PointData Scalars="c">
+        <DataArray type="Float32" Name="c" NumberOfComponents="1" format="ascii">
+          0.987413 0.967792 0.987952 0.96968 0.835216 0.846695 0.315888 0.347015 0.07633 0.0842153 0.0310669 0.0318347
+          0.98934 0.974433 0.876081 0.451628 0.108122 0.0343987 0.990994 0.979831 0.908563 0.599035 0.142578 0.0385368
+          0.992267 0.983696 0.929883 0.688029 0.17195 0.0424578 0.992715 0.984891 0.935745 0.709774 0.181316 0.0438416
+          0.992203 0.983164 0.926316 0.673731 0.166303 0.0418624 0.990913 0.978868 0.901396 0.565368 0.133737 0.0379597
+          0.989316 0.97332 0.867197 0.415015 0.0999852 0.034596 0.988025 0.968704 0.838855 0.324748 0.0786051 0.0330494
+          0.987533 0.966931 0.828442 0.299419 0.0719689 0.0327484
+        </DataArray>
+        <DataArray type="Float32" Name="mu" NumberOfComponents="1" format="ascii">
+          -0.582482 -0.579776 -0.5887 -0.593969 -0.515998 -0.568131 -0.114131 -0.238969 1.04176 0.96415 2.52288 2.46061
+          -0.59644 -0.613863 -0.646813 -0.49582 0.808299 2.31556 -0.588708 -0.60506 -0.635295 -0.505148 0.717069 2.17269
+          -0.566343 -0.570571 -0.549029 -0.307996 0.726686 2.0862 -0.545819 -0.543905 -0.497521 -0.22 0.746878 2.05582
+          -0.53554 -0.541183 -0.528833 -0.312476 0.723869 2.06566 -0.524652 -0.53964 -0.570403 -0.464335 0.727907 2.11388
+          -0.50005 -0.510371 -0.52179 -0.33466 0.833541 2.19285 -0.468666 -0.462752 -0.404704 -0.0578805 0.982785 2.26844
+          -0.453862 -0.438902 -0.343636 0.0588401 1.05113 2.29946
+        </DataArray>
+      </PointData>
+      <CellData Scalars="process rank">
+        <DataArray type="Float32" Name="process rank" NumberOfComponents="1" format="ascii">
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0 0 0 0 0 0 0 0 0 0 0
+          0 0
+        </DataArray>
+      </CellData>
+      <Points>
+        <DataArray type="Float32" Name="Coordinates" NumberOfComponents="3" format="ascii">
+          0 0 0 0.1 0 0 0 0.1 0 0.1 0.1 0
+          0.2 0 0 0.2 0.1 0 0.3 0 0 0.3 0.1 0
+          0.4 0 0 0.4 0.1 0 0.5 0 0 0.5 0.1 0
+          0 0.2 0 0.1 0.2 0 0.2 0.2 0 0.3 0.2 0
+          0.4 0.2 0 0.5 0.2 0 0 0.3 0 0.1 0.3 0
+          0.2 0.3 0 0.3 0.3 0 0.4 0.3 0 0.5 0.3 0
+          0 0.4 0 0.1 0.4 0 0.2 0.4 0 0.3 0.4 0
+          0.4 0.4 0 0.5 0.4 0 0 0.5 0 0.1 0.5 0
+          0.2 0.5 0 0.3 0.5 0 0.4 0.5 0 0.5 0.5 0
+          0 0.6 0 0.1 0.6 0 0.2 0.6 0 0.3 0.6 0
+          0.4 0.6 0 0.5 0.6 0 0 0.7 0 0.1 0.7 0
+          0.2 0.7 0 0.3 0.7 0 0.4 0.7 0 0.5 0.7 0
+          0 0.8 0 0.1 0.8 0 0.2 0.8 0 0.3 0.8 0
+          0.4 0.8 0 0.5 0.8 0 0 0.9 0 0.1 0.9 0
+          0.2 0.9 0 0.3 0.9 0 0.4 0.9 0 0.5 0.9 0
+          0 1 0 0.1 1 0 0.2 1 0 0.3 1 0
+          0.4 1 0 0.5 1 0
+        </DataArray>
+      </Points>
+      <Cells>
+        <DataArray type="Int32" Name="connectivity" NumberOfComponents="1" format="ascii">
+          0 1 3 2 1 4 5 3 4 6 7 5
+          6 8 9 7 8 10 11 9 2 3 13 12
+          3 5 14 13 5 7 15 14 7 9 16 15
+          9 11 17 16 12 13 19 18 13 14 20 19
+          14 15 21 20 15 16 22 21 16 17 23 22
+          18 19 25 24 19 20 26 25 20 21 27 26
+          21 22 28 27 22 23 29 28 24 25 31 30
+          25 26 32 31 26 27 33 32 27 28 34 33
+          28 29 35 34 30 31 37 36 31 32 38 37
+          32 33 39 38 33 34 40 39 34 35 41 40
+          36 37 43 42 37 38 44 43 38 39 45 44
+          39 40 46 45 40 41 47 46 42 43 49 48
+          43 44 50 49 44 45 51 50 45 46 52 51
+          46 47 53 52 48 49 55 54 49 50 56 55
+          50 51 57 56 51 52 58 57 52 53 59 58
+          54 55 61 60 55 56 62 61 56 57 63 62
+          57 58 64 63 58 59 65 64
+        </DataArray>
+        <DataArray type="Int32" Name="offsets" NumberOfComponents="1" format="ascii">
+          4 8 12 16 20 24 28 32 36 40 44 48
+          52 56 60 64 68 72 76 80 84 88 92 96
+          100 104 108 112 116 120 124 128 132 136 140 144
+          148 152 156 160 164 168 172 176 180 184 188 192
+          196 200
+        </DataArray>
+        <DataArray type="UInt8" Name="types" NumberOfComponents="1" format="ascii">
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9
+        </DataArray>
+      </Cells>
+    </Piece>
+  </UnstructuredGrid>
+</VTKFile>
diff --git a/test/references/example_cahn_hilliard_parallel_p1-reference.vtu b/test/references/example_cahn_hilliard_parallel_p1-reference.vtu
new file mode 100644
index 0000000000000000000000000000000000000000..654a428525ab4430f94642d8aacaa522a2cd99e2
--- /dev/null
+++ b/test/references/example_cahn_hilliard_parallel_p1-reference.vtu
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<VTKFile type="UnstructuredGrid" version="0.1" byte_order="LittleEndian">
+  <UnstructuredGrid>
+    <Piece NumberOfCells="50" NumberOfPoints="66">
+      <PointData Scalars="c">
+        <DataArray type="Float32" Name="c" NumberOfComponents="1" format="ascii">
+          0.0310669 0.0454055 0.0318347 0.0417179 0.151223 0.122843 0.60494 0.44536 0.913399 0.842182 0.97646 0.9239
+          0.0343987 0.0342536 0.0743882 0.197663 0.49711 0.669889 0.0385368 0.0284181 0.0439069 0.0838457 0.148188 0.187137
+          0.0424578 0.0257314 0.0319396 0.0451773 0.059939 0.066897 0.0438416 0.0254117 0.0303727 0.040822 0.0512762 0.0558646
+          0.0418624 0.0274558 0.0386987 0.0636586 0.0966672 0.114176 0.0379597 0.0335398 0.0679441 0.156054 0.307864 0.41219
+          0.034596 0.0451329 0.133094 0.438475 0.796547 0.869974 0.0330494 0.0589986 0.221886 0.75329 0.949963 0.987869
+          0.0327484 0.0656509 0.268929 0.820439 0.980281 1.00762
+        </DataArray>
+        <DataArray type="Float32" Name="mu" NumberOfComponents="1" format="ascii">
+          2.52288 4.1823 2.46061 4.08921 6.01253 5.8368 7.70006 7.56053 8.05424 8.02932 8.11412 8.13276
+          2.31556 3.86377 5.42192 6.84719 7.90439 8.06514 2.17269 3.62044 4.99448 6.19814 7.04558 7.35191
+          2.0862 3.45163 4.71887 5.78889 6.52484 6.78999 2.05582 3.39119 4.64108 5.71237 6.46686 6.74404
+          2.06566 3.42621 4.73554 5.92798 6.85212 7.22199 2.11388 3.51364 4.91738 6.26625 7.44102 8.01139
+          2.19285 3.59492 5.03798 6.51027 7.23419 7.48124 2.26844 3.63308 5.01078 6.15979 6.78308 6.98309
+          2.29946 3.63974 4.95753 5.99225 6.59989 6.79676
+        </DataArray>
+      </PointData>
+      <CellData Scalars="process rank">
+        <DataArray type="Float32" Name="process rank" NumberOfComponents="1" format="ascii">
+          1 1 1 1 1 1 1 1 1 1 1 1
+          1 1 1 1 1 1 1 1 1 1 1 1
+          1 1 1 1 1 1 1 1 1 1 1 1
+          1 1 1 1 1 1 1 1 1 1 1 1
+          1 1
+        </DataArray>
+      </CellData>
+      <Points>
+        <DataArray type="Float32" Name="Coordinates" NumberOfComponents="3" format="ascii">
+          0.5 0 0 0.6 0 0 0.5 0.1 0 0.6 0.1 0
+          0.7 0 0 0.7 0.1 0 0.8 0 0 0.8 0.1 0
+          0.9 0 0 0.9 0.1 0 1 0 0 1 0.1 0
+          0.5 0.2 0 0.6 0.2 0 0.7 0.2 0 0.8 0.2 0
+          0.9 0.2 0 1 0.2 0 0.5 0.3 0 0.6 0.3 0
+          0.7 0.3 0 0.8 0.3 0 0.9 0.3 0 1 0.3 0
+          0.5 0.4 0 0.6 0.4 0 0.7 0.4 0 0.8 0.4 0
+          0.9 0.4 0 1 0.4 0 0.5 0.5 0 0.6 0.5 0
+          0.7 0.5 0 0.8 0.5 0 0.9 0.5 0 1 0.5 0
+          0.5 0.6 0 0.6 0.6 0 0.7 0.6 0 0.8 0.6 0
+          0.9 0.6 0 1 0.6 0 0.5 0.7 0 0.6 0.7 0
+          0.7 0.7 0 0.8 0.7 0 0.9 0.7 0 1 0.7 0
+          0.5 0.8 0 0.6 0.8 0 0.7 0.8 0 0.8 0.8 0
+          0.9 0.8 0 1 0.8 0 0.5 0.9 0 0.6 0.9 0
+          0.7 0.9 0 0.8 0.9 0 0.9 0.9 0 1 0.9 0
+          0.5 1 0 0.6 1 0 0.7 1 0 0.8 1 0
+          0.9 1 0 1 1 0
+        </DataArray>
+      </Points>
+      <Cells>
+        <DataArray type="Int32" Name="connectivity" NumberOfComponents="1" format="ascii">
+          0 1 3 2 1 4 5 3 4 6 7 5
+          6 8 9 7 8 10 11 9 2 3 13 12
+          3 5 14 13 5 7 15 14 7 9 16 15
+          9 11 17 16 12 13 19 18 13 14 20 19
+          14 15 21 20 15 16 22 21 16 17 23 22
+          18 19 25 24 19 20 26 25 20 21 27 26
+          21 22 28 27 22 23 29 28 24 25 31 30
+          25 26 32 31 26 27 33 32 27 28 34 33
+          28 29 35 34 30 31 37 36 31 32 38 37
+          32 33 39 38 33 34 40 39 34 35 41 40
+          36 37 43 42 37 38 44 43 38 39 45 44
+          39 40 46 45 40 41 47 46 42 43 49 48
+          43 44 50 49 44 45 51 50 45 46 52 51
+          46 47 53 52 48 49 55 54 49 50 56 55
+          50 51 57 56 51 52 58 57 52 53 59 58
+          54 55 61 60 55 56 62 61 56 57 63 62
+          57 58 64 63 58 59 65 64
+        </DataArray>
+        <DataArray type="Int32" Name="offsets" NumberOfComponents="1" format="ascii">
+          4 8 12 16 20 24 28 32 36 40 44 48
+          52 56 60 64 68 72 76 80 84 88 92 96
+          100 104 108 112 116 120 124 128 132 136 140 144
+          148 152 156 160 164 168 172 176 180 184 188 192
+          196 200
+        </DataArray>
+        <DataArray type="UInt8" Name="types" NumberOfComponents="1" format="ascii">
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9 9 9 9 9 9 9 9 9 9 9
+          9 9
+        </DataArray>
+      </Cells>
+    </Piece>
+  </UnstructuredGrid>
+</VTKFile>