diff --git a/README.md b/README.md
index b4736659764719d1674dcef972a01035e3f04046..af64cb26b9cd61d72db8781703d6ea3bea7c8ba4 100644
--- a/README.md
+++ b/README.md
@@ -51,8 +51,8 @@ You will find the plots `mmdg_bulk.pdf`, `mmdg_interface.pdf` and `mmdg_total.pd
 Test Problems
 -------------
 
-The `dune-mmdg` module includes three test problems, `dg1` to `dg3`, for the bulk scheme and six test problems, `mmdg1` to `mmdg6`, for the coupled scheme.
-The test problems `dg2`, `mmdg2`, `mmdg5` and `mmdg6` correspond to the examples 5.1 to 5.4 in [1].
+The `dune-mmdg` module includes five test problems, `dg1` to `dg5`, for the bulk scheme and seven test problems, `mmdg1` to `mmdg7`, for the coupled scheme.
+The test problems `dg2`, `mmdg2`, `mmdg5`, `mmdg6` and `dg4`/`mmdg7` correspond to the examples 5.1, 5.2, 5.3, 5.4/5.5 and 5.6 in [1] in the given order.
 
 
 Parameters
@@ -61,16 +61,21 @@ Parameters
 For the bulk scheme the following parameters can be set in the file `parameterDG.ini` in the `src` directory:
 
 - `mu0`:   the prefactor of the penalty parameter (must be sufficiently large)
-- `problem`:   the name of a test problem (`dg1` to `dg3`) 
+- `problem`:   the name of a test problem (`dg1` to `dg5`) 
+- `dmax`:   the maximum value of the aperture function (only relevant for the problems `dg4` and `dg5` that include a fracture)
+- `dmin`:   the minimum value of the aperture function (only relevant for the problems `dg4` and `dg5` that include a fracture)
+- `solver`:   (optional) the name of the solver that is applied to the system of linear equations (`Cholmod` or `UMFPack`)
 - `fastEOC`:   (optional) exclude computationally expensive grids from the EOC loop
 
 For the coupled scheme the following parameters can be set in the file `parameterMMDG.ini` in the `src` directory:
 
 - `mu0`:   the prefactor of the penalty parameter (must be sufficiently large)
-- `problem`:   the name of a test problem (`mmdg1` to `mmdg6`) 
-- `d`:   the aperture of the fracture or the prefactor of the aperture function
+- `problem`:   the name of a test problem (`mmdg1` to `mmdg7`) 
+- `dmax`:   the maximum value of the aperture of the fracture or respective constant aperture value (mandatory for all problems)
+- `dmin`:   the minimum value of the aperture of the fracture (only relevant for problem `mmdg7`)
 - `xi`:   (optional) the value of the coupling parameter (must be larger than 0.5)
 - `gridfile`:   (optional) the prefix of a grid file name in the directory `src/grids`
+- `solver`:   (optional) the name of the solver that is applied to the system of linear equations (`Cholmod` or `UMFPack`)
 - `fastEOC`:   (optional) exclude computationally expensive grids from the EOC loop
 
 
diff --git a/dune/mmdg/clockhelper.hh b/dune/mmdg/clockhelper.hh
index 05c3ddc2afd28bba0deb357fc5f9edbcc0ca4790..850e1e49d0e82ca344ceea4ee4a780befd89f38c 100644
--- a/dune/mmdg/clockhelper.hh
+++ b/dune/mmdg/clockhelper.hh
@@ -3,6 +3,7 @@
 
 #include <chrono>
 
+//contains a function for run time measurements
 class ClockHelper
 {
   public:
@@ -12,8 +13,8 @@ class ClockHelper
     //precision of a microsecond
     static double elapsedRuntime(const Clock::time_point begin)
     {
-      return 1e-6*std::chrono::duration_cast<std::chrono::microseconds>
-        (Clock::now() - begin).count();;
+      return 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>
+        ( Clock::now() - begin ).count();;
     }
 };
 
diff --git a/dune/mmdg/dg.hh b/dune/mmdg/dg.hh
index 623c82561d0d696e62e2478319a2623e94796fd5..8a00b9bc87c1205c1abb56a5b8e237ad5f8ef674 100644
--- a/dune/mmdg/dg.hh
+++ b/dune/mmdg/dg.hh
@@ -14,9 +14,11 @@
 #include <dune/istl/bcrsmatrix.hh>
 #include <dune/istl/solver.hh>
 #include <dune/istl/cholmod.hh>
+#include <dune/istl/umfpack.hh>
 
 #include <dune/mmdg/nonconformingp1vtkfunction.hh>
 #include <dune/mmdg/eigenvaluehelper.hh>
+#include <dune/mmdg/solvertype.hh>
 
 template<class GridView, class Mapper, class Problem>
 class DG
@@ -40,12 +42,13 @@ public:
   using QRulesEdge = Dune::QuadratureRules<Scalar, dim-1>;
 
   //constructor
-  DG (const GridView& gridView, const Mapper& mapper, const Problem& problem) :
+  DG (const GridView& gridView, const Mapper& mapper, const Problem& problem,
+    const SolverType& solver) :
     gridView_(gridView), mapper_(mapper), problem_(problem),
-    dof_((1 + dim) * gridView.size(0))
+    dof_((1 + dim) * gridView.size(0)), solver_(solver)
     {
       //initialize stiffness matrix A, load vector b and solution vector d
-      A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit); //TODO
+      A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit);
       b = Vector(dof_);
       d = Vector(dof_);
     }
@@ -56,16 +59,31 @@ public:
     assembleSLE(mu0);
     A->compress();
 
+    //solve system of linear equations
     Dune::InverseOperatorResult result;
-    Dune::Cholmod<Vector> solver;
-    solver.setMatrix(*A);
-    solver.apply(d, b, result);
+
+    if (solver_ == SolverType::Cholmod)
+    {
+      Dune::Cholmod<Vector> solver;
+      solver.setMatrix(*A);
+      solver.apply(d, b, result);
+    }
+    else if (solver_ == SolverType::UMFPack)
+    {
+      Dune::UMFPack<Matrix> solver(*A);
+      solver.apply(d, b, result);
+    }
+    else
+    {
+      DUNE_THROW(Dune::Exception, "ERROR: Specified solver type not "
+        "implemented");
+    }
 
     //write solution to a vtk file
     writeVTKoutput();
   }
 
-  //compute L2 error using a quadrature rule
+  //computes the L2 error using a quadrature rule
   Scalar computeL2error(const int quadratureOrder = 5)
   {
     if (!problem_.hasExactSolution())
@@ -112,12 +130,14 @@ public:
   const int dof_; //degrees of freedom
 
 protected:
+  //constructor with custom value of dof_
   DG (const GridView& gridView, const Mapper& mapper, const Problem& problem,
-    const int dof) :
-    gridView_(gridView), mapper_(mapper), problem_(problem), dof_(dof)
+    const SolverType solver, const int dof) :
+    gridView_(gridView), mapper_(mapper), problem_(problem), dof_(dof),
+    solver_(solver)
     {
       //initialize stiffness matrix A, load vector b and solution vector d
-      A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit); //TODO
+      A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit);
       b = Vector(dof_);
       d = Vector(dof_);
     }
@@ -151,7 +171,7 @@ protected:
       //in the system of linear equations (SLE) Ad = b,
       //the index elemIdxSLE refers to the basis function phi_elem,0
       //and the indices elemIdxSLE + i + 1, i = 1,...,dim, refer to the
-      //basis function phi_elem,i
+      //basis functions phi_elem,i
       const int elemIdxSLE = (dim + 1)*elemIdx;
 
       //lambda to fill load vector b using a quadrature rule
@@ -212,7 +232,7 @@ protected:
 
         //create storage for multiply used integral values
         //linearIntegrals[i] = int_intersct x[i] ds
-        //quadraticIntregrals[i][j] = int_intersct x[i]*x[j] ds //NOTE: is there a better type for a symmetric matrix?
+        //quadraticIntregrals[i][j] = int_intersct x[i]*x[j] ds
         //KIntegrals[i] = int_intersct K[:,i]*normal ds
         //KIntegralsX[i][j] = int_intersct x[j]*(K[:,i]*normal) ds
         Coordinate linearIntegrals(0.0);
@@ -267,7 +287,7 @@ protected:
             }
           };
 
-        //apply quadrature rules in intersct
+        //apply quadrature rules on intersct
         applyQuadratureRule(intersctGeo, rule_2ndOrder, lambda_2ndOrder);
         applyQuadratureRule(intersctGeo, rule_K_Edge, lambda_K_Edge);
         applyQuadratureRule(intersctGeo, rule_Kplus1_Edge, lambda_Kplus1_Edge);
@@ -561,6 +581,7 @@ protected:
   std::shared_ptr<Matrix> A; //stiffness matrix
   Vector b; //load vector
   Vector d; //solution vector
+  SolverType solver_; //solver type (Cholmod or UMFPack)
 
 private:
   //writes the solution to a vtk file
diff --git a/dune/mmdg/eigenvaluehelper.hh b/dune/mmdg/eigenvaluehelper.hh
index a3e9cf0110cf2db8cb68bd30bea57c92d60f4a14..7fe56886e13b5457466458d04b91826281c81655 100644
--- a/dune/mmdg/eigenvaluehelper.hh
+++ b/dune/mmdg/eigenvaluehelper.hh
@@ -10,7 +10,7 @@
 
 /** \file
  * \brief Eigenvalue computations for the Dune::FieldMatrix class
- * NOTE: taken from DUNE-common, fmatrixev.hh, with adapted tolerance
+ * NOTE: taken from DUNE-common (fmatrixev.hh) with minor changes
  */
 class EigenvalueHelper {
 
diff --git a/dune/mmdg/mmdg.hh b/dune/mmdg/mmdg.hh
index a83541dbf9d2d190a9b2c948f63fc04c0adfa8df..0889dafd7bd1519bd9a1b3c4de3be1d53bebee0b 100644
--- a/dune/mmdg/mmdg.hh
+++ b/dune/mmdg/mmdg.hh
@@ -30,20 +30,36 @@ public:
   //constructor
   MMDG (const GridView& gridView, const Mapper& mapper,
     const InterfaceGridView& iGridView, const InterfaceMapper& iMapper,
-    const Problem& problem) :
-    Base(gridView, mapper, problem,
+    const Problem& problem, const SolverType& solver) :
+    Base(gridView, mapper, problem, solver,
       (1 + dim) * gridView.size(0) + dim * iGridView.size(0)),
     iGridView_(iGridView), iMapper_(iMapper) {}
 
   const void operator() (const Scalar mu0, const Scalar xi)
   {
+    //assemble stiffness matrix A and load vector b
     assembleSLE(mu0, xi);
     Base::A->compress();
 
+    //solve system of linear equations
     Dune::InverseOperatorResult result;
-    Dune::Cholmod<Vector> solver;
-    solver.setMatrix(*Base::A);
-    solver.apply(Base::d, Base::b, result);
+
+    if (Base::solver_ == SolverType::Cholmod)
+    {
+      Dune::Cholmod<Vector> solver;
+      solver.setMatrix(*Base::A);
+      solver.apply(Base::d, Base::b, result);
+    }
+    else if (Base::solver_ == SolverType::UMFPack)
+    {
+      Dune::UMFPack<Matrix> solver(*Base::A);
+      solver.apply(Base::d, Base::b, result);
+    }
+    else
+    {
+      DUNE_THROW(Dune::Exception, "ERROR: Specified solver type not "
+        "implemented");
+    }
 
     //write solution to a vtk file
     writeVTKoutput();
@@ -51,7 +67,7 @@ public:
 
   //compute L2 errors using quadrature rules,
   //returns {error(bulk), error(interface), error(total)},
-  //the total error is calculated using the norm
+  //the total error is calculated with respect to the norm
   // norm = sqrt( ||.||^2_L2(bulk) + ||.||^2_L2(interface) )
   const std::array<Scalar, 3> computeL2error(const int quadratureOrder = 5)
   {
@@ -90,8 +106,8 @@ public:
       Base::applyQuadratureRule(iGeo, qrule, qlambda);
     }
 
-    return {bulkError, sqrt(interfaceError),
-      sqrt(bulkError * bulkError + interfaceError)};
+    return { bulkError, sqrt(interfaceError),
+      sqrt(bulkError * bulkError + interfaceError) };
   }
 
   const InterfaceGridView& iGridView_;
@@ -147,6 +163,7 @@ private:
     //and load vector b with bulk entries
     Base::assembleSLE(mu0);
 
+    //fill in coupling and interface entries
     for (const auto& iElem : elements(iGridView_))
     {
       const int iElemIdx = iMapper_.index(iElem);
@@ -878,6 +895,8 @@ private:
     return iBasis;
   }
 
+  //write exakt and numerical bulk and interface solution as well as the
+  //aperture function of the problem to vtk files
   void writeVTKoutput () const
   {
     //degrees of freedom of bulk and interface grids
@@ -894,6 +913,7 @@ private:
     //create the output using a linear interpolation for each interface element
     Dune::DynamicVector<Scalar> iPressure(interfaceDOF, 0.0);
     Dune::DynamicVector<Scalar> exactIPressure(interfaceDOF, 0.0);
+    Dune::DynamicVector<Scalar> aperture(interfaceDOF, 0.0);
 
     for (const auto& iElem : elements(iGridView_))
     {
@@ -914,6 +934,10 @@ private:
             Base::problem_.exactInterfaceSolution(iGeo.corner(k));
         }
 
+        //aperture evaluated at the kth corner of iElem
+        aperture[iElemIdxOutput + k] =
+          Base::problem_.aperture(iGeo.corner(k));
+
         //contribution of the basis function
         // phi_iElem,0 (x) = indicator(iElem);
         //at the kth corner of iElem
@@ -934,6 +958,8 @@ private:
       vtkWriter(iGridView_, Dune::VTK::nonconforming);
     vtkWriter.addVertexData( std::shared_ptr<const VTKFunction>(
       new P1Function(iGridView_, iPressure, "interfacePressure")));
+    vtkWriter.addVertexData( std::shared_ptr<const VTKFunction>(
+      new P1Function(iGridView_, aperture, "aperture")));
 
     if (Base::problem_.hasExactSolution())
     {
diff --git a/dune/mmdg/nonconformingp1vtkfunction.hh b/dune/mmdg/nonconformingp1vtkfunction.hh
index 9ae9ec80968a149730263320846d4e4715cbfb0e..45a69ad7582d8e8af9245c9ff7c33063ad3ba4f8 100644
--- a/dune/mmdg/nonconformingp1vtkfunction.hh
+++ b/dune/mmdg/nonconformingp1vtkfunction.hh
@@ -1,8 +1,8 @@
 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 // vi: set et ts=4 sw=2 sts=2:
 
-#ifndef DUNE_MMFD_FUNCTION_HH
-#define DUNE_MMFD_FUNCTION_HH
+#ifndef DUNE_MMDG_FUNCTION_HH
+#define DUNE_MMDG_FUNCTION_HH
 
 #include <string>
 
@@ -17,6 +17,7 @@
 #include <dune/grid/io/file/vtk/common.hh>
 #include <dune/grid/io/file/vtk/function.hh>
 
+//NOTE: without changes from DUNE-MMFD by Samuel Burbulla
 namespace Dune
 {
   //////////////////////////////////////////////////////////////////////
@@ -143,4 +144,4 @@ namespace Dune
 
 } // namespace Dune
 
-#endif // DUNE_MMFD_FUNCTION_HH
+#endif // DUNE_MMDG_FUNCTION_HH
diff --git a/dune/mmdg/problems/coupleddgproblem.hh b/dune/mmdg/problems/coupleddgproblem.hh
index 9f7774ff6e3611f92dfcf8b16d21727815fda430..e45f08dbf889e9955da3cc97e45a0025c5ab230c 100644
--- a/dune/mmdg/problems/coupleddgproblem.hh
+++ b/dune/mmdg/problems/coupleddgproblem.hh
@@ -3,7 +3,7 @@
 
 #include <dune/mmdg/problems/dgproblem.hh>
 
-//abstract class providing an interface for a coupled flow problem in a
+//abstract class that provides an interface for a coupled flow problem in a
 //fractured porous medium that is to be solved with a coupled discontinuous
 //Galerkin scheme
 template<class Coordinate, class Scalar = double>
@@ -38,12 +38,13 @@ public:
     return Coordinate(0.0);
   }
 
+  //interface boundary condition at position pos
   virtual Scalar interfaceBoundary(const Coordinate& pos) const
   {
     return exactInterfaceSolution(pos);
   }
 
-  //tangential permeability per aperture tensor of the interface at position pos
+  //tangential permeability per aperture of the interface at position pos
   virtual Matrix Kparallel (const Coordinate& pos) const
   {
     Matrix permeability(0.0);
diff --git a/dune/mmdg/problems/dgproblem.hh b/dune/mmdg/problems/dgproblem.hh
index 38ed3077b35279cf29c0d64ba1e5fc92c46d603d..4cd466905c396d72fb8ee6de7a088ecef07d414e 100644
--- a/dune/mmdg/problems/dgproblem.hh
+++ b/dune/mmdg/problems/dgproblem.hh
@@ -1,8 +1,8 @@
 #ifndef __DUNE_MMDG_DGPROBLEM_HH__
 #define __DUNE_MMDG_DGPROBLEM_HH__
 
-//abstract class providing an interface for a problem that is to be solved with
-//a discontinuous Galerkin scheme
+//abstract class that provides an interface for a problem that is to be solved
+//with a discontinuous Galerkin scheme
 template<class Coordinate, class Scalar = double>
 class DGProblem
 {
diff --git a/dune/mmdg/problems/dgproblem1.hh b/dune/mmdg/problems/dgproblem1.hh
index 39f67481129a76e9217813072d0bf0cf96c54d10..52ca8ea29375e169269508989738f4ac05a0152d 100644
--- a/dune/mmdg/problems/dgproblem1.hh
+++ b/dune/mmdg/problems/dgproblem1.hh
@@ -11,9 +11,9 @@ class DGProblem1 : public DGProblem<Coordinate, Scalar>
     static constexpr int dim = Coordinate::dimension;
 
     //the exact solution at position pos
-    //1d: f(x)     = 0.5*x^2,
-    //2d: f(x,y)   = 0.5*x^2*y^2,
-    //3d: f(x,y,z) = 0.5*x^2*y^2*z^2
+    //1d: f(x)     = 0.5 * x^2,
+    //2d: f(x,y)   = 0.5 * x^2 * y^2,
+    //3d: f(x,y,z) = 0.5 * x^2 * y^2 * z^2
     Scalar exactSolution (const Coordinate& pos) const
     {
       Scalar solution(0.5);
@@ -46,7 +46,7 @@ class DGProblem1 : public DGProblem<Coordinate, Scalar>
       }
 
       if constexpr (dim == 3)
-      { //q(x,y,z) = -x^2*y^2 - x^2*z^2 - y^2*z^2
+      { //q(x,y,z) = -x^2 * y^2 - x^2 * z^2 - y^2 * z^2
         Scalar pos1_2 = pos[1] * pos[1];
         Scalar pos2_2 = pos[2] * pos[2];
         return -pos[0] * pos[0] * (pos1_2 + pos2_2) - pos1_2 * pos2_2;
diff --git a/dune/mmdg/problems/dgproblem2.hh b/dune/mmdg/problems/dgproblem2.hh
index 5d8240452bc414b30a6f886b73bdc64d0068709e..96415cd3611b1817fb211f33f852d975ba3bbfa8 100644
--- a/dune/mmdg/problems/dgproblem2.hh
+++ b/dune/mmdg/problems/dgproblem2.hh
@@ -3,6 +3,7 @@
 
 #include <dune/mmdg/problems/dgproblem.hh>
 
+//a test problem with anisotropic permeability but without fracture
 template<class Coordinate, class Scalar = double>
 class DGProblem2 : public DGProblem<Coordinate, Scalar>
 {
@@ -17,7 +18,6 @@ class DGProblem2 : public DGProblem<Coordinate, Scalar>
     //3d: p(x,y,z) = x^2 + y^2 + z^2
     Scalar exactSolution (const Coordinate& pos) const
     {
-      //return pos * Coordinate(1.0);
       return pos * pos;
     }
 
diff --git a/dune/mmdg/problems/dgproblem3.hh b/dune/mmdg/problems/dgproblem3.hh
index 21659d847274b1984e4a126d6f1446e68b896894..1ba4e5d6816f178fa835590b8e6bfd847d95e138 100644
--- a/dune/mmdg/problems/dgproblem3.hh
+++ b/dune/mmdg/problems/dgproblem3.hh
@@ -2,11 +2,9 @@
 #define __DUNE_MMDG_DGPROBLEM3_HH__
 
 #include <cmath>
-#include <string>
-
 #include <dune/mmdg/problems/dgproblem.hh>
 
-//Poisson problem with right side q = -1
+//Poisson problem with right side q = -1 and homogeneous Dirichlet boundary
 template<class Coordinate, class Scalar = double>
 class DGProblem3 : public DGProblem<Coordinate, Scalar>
 {
@@ -76,13 +74,13 @@ class DGProblem3 : public DGProblem<Coordinate, Scalar>
     //source term
     Scalar q (const Coordinate& pos) const
     {
-      return Scalar(-1.0);
+      return -1.0;
     }
 
     //boundary condition at position pos
-    virtual Scalar boundary (const Coordinate& pos) const
+    Scalar boundary (const Coordinate& pos) const
     {
-      return Scalar(0.0);
+      return 0.0;
     }
 };
 
diff --git a/dune/mmdg/problems/dgproblem4.hh b/dune/mmdg/problems/dgproblem4.hh
new file mode 100644
index 0000000000000000000000000000000000000000..07b8dd0aea89b1e81d52ece3c0d719337f8bb365
--- /dev/null
+++ b/dune/mmdg/problems/dgproblem4.hh
@@ -0,0 +1,164 @@
+#ifndef __DUNE_MMDG_DGPROBLEM4_HH__
+#define __DUNE_MMDG_DGPROBLEM4_HH__
+
+#include <dune/mmdg/problems/dgproblem.hh>
+#include <cmath>
+
+//a problem with cosine-shaped fracture and continuous pressure and Darcy
+//velocity
+template<class Coordinate, class Scalar = double>
+class DGProblem4 : public DGProblem<Coordinate, Scalar>
+{
+  public:
+    static constexpr int dim = Coordinate::dimension;
+    using Base = DGProblem<Coordinate, Scalar>;
+    using Matrix = typename Base::Matrix;
+
+    //constructor, require dim != 1
+    DGProblem4 (const Scalar dmin, const Scalar dmax) : dmin_(dmin), dmax_(dmax)
+    {
+      if (dim == 1)
+      {
+        DUNE_THROW(Dune::Exception,
+          "Problem dg4 is not implemented for dimension = " +
+          std::to_string(dim) + "!");
+      }
+    }
+
+    //the exact solution at position pos
+    Scalar exactSolution (const Coordinate& pos) const
+    {
+      const Scalar d = aperture(pos);
+
+      if ( pos[0] < 0.5 * ( 1.0 - d ) )
+      { //pos in Omega_1 (left of the fracture)
+        return 2.0 * ( pos[0] + d ) * exp(-d);
+      }
+
+      if ( pos[0] > 0.5 * ( 1.0 + d ) )
+      { //pos in Omega_2 (right of the fracture)
+        return 2.0 * pos[0] * exp(d);
+      }
+
+      //pos in Omega_R (inside the fracture)
+      return ( 1.0 + d ) * exp( 2.0 * pos[0] - 1.0 );
+    }
+
+    //exact solution is implemented
+    bool hasExactSolution() const
+    {
+      return true;
+    };
+
+    //source term at position pos
+    Scalar q (const Coordinate& pos) const
+    {
+      const Scalar d = aperture(pos);
+      Scalar dPrime2 = aperturePrime(pos);
+      dPrime2 *= dPrime2;
+      const Scalar dPrimePrime = aperturePrimePrime(pos);
+
+
+      if ( pos[0] < 0.5 * ( 1.0 - d ) )
+      { //pos in Omega_1 (left of the fracture)
+        return -2.0 * exp(-d) / ( 1.0 - d ) * ( ( 1.0 - pos[0] - d )
+          * ( dPrimePrime + dPrime2 * d / ( 1.0 - d ) ) - dPrime2 );
+      }
+
+      if ( pos[0] > 0.5 * ( 1.0 + d ) )
+      { //pos in Omega_2 (right of the fracture)
+        return -2.0 * pos[0] * exp(d) / ( 1.0 + d )
+          * ( dPrimePrime + dPrime2 * d / ( 1.0 + d ) );
+      }
+
+      //pos in Omega_R (inside the fracture)
+      return
+        -exp(2.0 * pos[0] - 1) * ( 4.0 + dPrimePrime );
+    }
+
+    //permeability tensor at position pos
+    Matrix K (const Coordinate& pos) const
+    {
+      const Scalar d = aperture(pos);
+
+      Matrix permeability(0.0);
+
+      if ( pos[0] < 0.5 * ( 1.0 - d ) )
+      { //pos in Omega_1 (left of the fracture)
+        permeability[0][0] = 1.0;
+
+        for (int i = 1; i < dim; i++)
+        {
+          permeability[i][i] = 1.0 / ( 1.0 - d );
+        }
+      }
+      else if ( pos[0] > 0.5 * ( 1.0 + d ) )
+      { //pos in Omega_2 (right of the fracture)
+        permeability[0][0] = 1.0;
+
+        for (int i = 1; i < dim; i++)
+        {
+          permeability[i][i] = 1.0 / ( 1.0 + d );
+        }
+      }
+      else
+      { //pos in Omega_R (inside the fracture)
+        permeability[0][0] = 1.0 / ( 1.0 + d );
+
+        for (int i = 1; i < dim; i++)
+        {
+          permeability[i][i] = 1.0;
+        }
+      }
+
+      return permeability;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over x * q(x)
+    int quadratureOrder_q () const
+    {
+      return 10;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over x * boundary(x) and K(x) * boundary(x)
+    int quadratureOrderBoundary () const
+    {
+      return 10;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over an entry K[i][j] of the permeability tensor
+    int quadratureOrder_K () const
+    {
+      return 10;
+    }
+
+  private:
+    //aperture of the fracture at position pos
+    const Scalar aperture (const Coordinate& pos) const
+    {
+      return dmin_ + 0.5 * ( dmax_ - dmin_ ) *
+        ( 1.0 + std::cos(8.0 * M_PI * pos[1]) );
+    }
+
+    //derivative of aperture at position pos
+    const Scalar aperturePrime (const Coordinate& pos) const
+    {
+      return -4.0 * M_PI * ( dmax_ - dmin_ ) * std::sin(8.0 * M_PI * pos[1]);
+    }
+
+    //second derivative of aperture at position pos
+    const Scalar aperturePrimePrime (const Coordinate& pos) const
+    {
+      return -32.0 * M_PI * M_PI * ( dmax_ - dmin_ )
+        * std::cos(8.0 * M_PI * pos[1]);
+    }
+
+    const Scalar dmin_; //minimum aperture of the fracture
+    const Scalar dmax_; //maximum aperture of the fracture
+
+};
+
+#endif
diff --git a/dune/mmdg/problems/dgproblem5.hh b/dune/mmdg/problems/dgproblem5.hh
new file mode 100644
index 0000000000000000000000000000000000000000..678c0e5283d87b8e6db6558ffc6362a31c65a397
--- /dev/null
+++ b/dune/mmdg/problems/dgproblem5.hh
@@ -0,0 +1,131 @@
+#ifndef __DUNE_MMDG_DGPROBLEM5_HH__
+#define __DUNE_MMDG_DGPROBLEM5_HH__
+
+#include <dune/mmdg/problems/dgproblem.hh>
+#include <cmath>
+
+//a problem with a cosine-shaped fracture and continuous pressure
+//NOTE: This problem does not show convergence as the normal Darcy velocity is
+//      only continuous with respect to the normal of the hyperplane
+//      Gamma = { x_1 = 0.5 } but not with respect to the normal of the actual
+//      interfaces between the bulk and fracture domains
+template<class Coordinate, class Scalar = double>
+class DGProblem5 : public DGProblem<Coordinate, Scalar>
+{
+  public:
+    static constexpr int dim = Coordinate::dimension;
+    using Base = DGProblem<Coordinate, Scalar>;
+    using Matrix = typename Base::Matrix;
+
+    static constexpr Scalar Kbulk = 1.0; //bulk permeability
+    static constexpr Scalar K_par = 3.0; //tangential fracture permeability
+    static constexpr Scalar K_perp = 0.5; //normal fracture permeability
+
+    //constructor, require dim != 1
+    DGProblem5 (const Scalar dmin, const Scalar dmax) : dmin_(dmin), dmax_(dmax)
+    {
+      if (dim == 1)
+      {
+        DUNE_THROW(Dune::Exception,
+          "Problem dg5 is not implemented for dimension = " +
+          std::to_string(dim) + "!");
+      }
+    }
+
+    //the exact solution at position pos
+    Scalar exactSolution (const Coordinate& pos) const
+    {
+      if ( pos[0] < 0.5 * (1.0 - aperture(pos)) )
+      { //pos in Omega_1 (left of the fracture)
+        return -0.5 * ( pos[0] - 0.5 ) * pos[1] * aperture(pos);
+      }
+
+      if ( pos[0] > 0.5 * (1.0 + aperture(pos)) )
+      { //pos in Omega_2 (right of the fracture)
+        return 0.5 * ( pos[0] - 0.5 ) * pos[1] * aperture(pos);
+      }
+
+      //pos in Omega_R (inside the fracture)
+      return ( pos[0] - 0.5 ) * ( pos[0] - 0.5 ) * pos[1];
+    }
+
+    //exact solution is implemented
+    bool hasExactSolution() const
+    {
+      return true;
+    };
+
+    //source term at position pos
+    Scalar q (const Coordinate& pos) const
+    {
+      if ( pos[0] < 0.5 * (1.0 - aperture(pos)) )
+      { //pos in Omega_1 (left of the fracture)
+        return -4.0 * M_PI * Kbulk * ( dmax_ - dmin_ ) *
+          ( pos[0] - 0.5 ) * ( std::sin(8.0 * M_PI * pos[1])
+            + 4.0 * M_PI * pos[1] * std::cos(8.0 * M_PI * pos[1]) );
+      }
+
+      if ( pos[0] > 0.5 * (1.0 + aperture(pos)) )
+      { //pos in Omega_2 (right of the fracture)
+        return 4.0 * M_PI * Kbulk * ( dmax_ - dmin_ ) *
+          ( pos[0] - 0.5 ) * ( std::sin(8.0 * M_PI * pos[1])
+            + 4.0 * M_PI * pos[1] * std::cos(8.0 * M_PI * pos[1]) );
+      }
+
+      //pos in Omega_R (inside the fracture)
+      return -2.0 * K_perp * pos[1];
+    }
+
+    //permeability tensor at position pos
+    Matrix K (const Coordinate& pos) const
+    {
+      Matrix permeability(0.0);
+
+      if ( pos[0] < 0.5 * (1.0 - aperture(pos)) ||
+        pos[0] > 0.5 * (1.0 + aperture(pos)))
+      { //pos in Omega_1 or Omega_2 (outside the fracture)
+        for (int i = 0; i < dim; i++)
+        {
+          permeability[i][i] = Kbulk;
+        }
+      }
+      else
+      { //pos in Omega_R (inside the fracture)
+        permeability[0][0] = K_perp;
+
+        for (int i = 1; i < dim; i++)
+        {
+          permeability[i][i] = K_par;
+        }
+      }
+
+      return permeability;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over x * q(x)
+    int quadratureOrder_q () const
+    {
+      return 10;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over x * boundary(x) and K(x) * boundary(x)
+    int quadratureOrderBoundary () const
+    {
+      return 10;
+    }
+
+  private:
+    //aperture of the fracture
+    const Scalar aperture (const Coordinate& pos) const
+    {
+      return dmin_ + 0.5 * ( dmax_ - dmin_ ) *
+        ( 1.0 + std::cos(8.0 * M_PI * pos[1]) );
+    }
+
+    const Scalar dmin_; //minimum aperture of the fracture
+    const Scalar dmax_; //maximum aperture of the fracture
+};
+
+#endif
diff --git a/dune/mmdg/problems/mmdgproblem1.hh b/dune/mmdg/problems/mmdgproblem1.hh
index f35a61ff999ac3eb073e87408dc67cf92c07a1b1..d581459eceb434ce520f374cb86d6f64c1021f32 100644
--- a/dune/mmdg/problems/mmdgproblem1.hh
+++ b/dune/mmdg/problems/mmdgproblem1.hh
@@ -4,7 +4,12 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem
+//a coupled dg problem wiht non-constant aperture
+//NOTE: To deal with the non-constant aperture, an adaption of the coupled DG
+//      scheme implemented in mmdg.hh is used to solve this problem. Thus, the
+//      interface source term and the tangential permeability per aperture
+//      inside the fracture are multiplied with the aperture function d in
+//      the following problem definition
 template<class Coordinate, class Scalar = double>
 class MMDGProblem1 : public CoupledDGProblem<Coordinate, Scalar>
 {
@@ -14,7 +19,7 @@ public:
   using Matrix = typename Base::Matrix;
 
   //constructor
-  MMDGProblem1 (const Scalar d) : d_(d) {}
+  MMDGProblem1 (const Scalar dmax) : d_ ( dmax / 1.01 ) {}
 
   //the exact bulk solution at position pos
   Scalar exactSolution (const Coordinate& pos) const
@@ -28,7 +33,7 @@ public:
     return 1.0;
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
@@ -37,7 +42,40 @@ public:
   //aperture d of the fracture at position pos
   Scalar aperture (const Coordinate& pos) const
   {
-    return d_;
+    return d_ * (pos[1] + 0.01);
+  }
+
+  //interface source term at position pos
+  //NOTE: contains an extra factor d
+  Scalar qInterface (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+    const Coordinate gradD = gradAperture(pos);
+
+    // q = -d * d'' - (d')^2    with extra factor d and d'' = 0
+    return -d * (gradD * gradD);
+  }
+
+  //tangential gradient of the aperture d of the fracture at position pos
+  Coordinate gradAperture (const Coordinate& pos) const
+  {
+    Coordinate gradD(0.0);
+    gradD[1] = d_;
+    return gradD;
+  }
+
+  //tangential permeability per aperture tensor of the interface at position pos
+  //NOTE: contains an extra factor d
+  Matrix Kparallel (const Coordinate& pos) const
+  {
+    Matrix permeability(0.0);
+
+    for (int i = 0; i < dim; i++)
+    {
+      permeability[i][i] = aperture(pos);
+    }
+
+    return permeability;
   }
 
   //returns the recommended quadrature order to compute an integral
@@ -47,8 +85,34 @@ public:
     return 2;
   }
 
+  //returns the recommended quadrature order to compute an integral
+  //over x * qInterface(x)
+  int quadratureOrder_qInterface () const
+  {
+    return 2;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over  x * d^2 * interfaceBoundary(x)
+  //and   x * d * interfaceBoundary(x) * (Kpar * grad(d))
+  //and   d^2 * interfaceBoundary(x) * Kpar
+  int quadratureOrderInterfaceBoundary () const
+  {
+    return 3;
+  }
+
+  //returns the recommended quadrature order to compute integrals
+  //over  x^2 * (Kpar * grad(d) * grad(d))
+  //and   x^2 * d^2
+  //and   x^2 * d * (Kpar * grad(d))
+  //and   x * d^2 * Kpar
+  int quadratureOrder_Kparallel () const
+  {
+    return 4;
+  }
+
 private:
-  Scalar d_; //aperture
+  Scalar d_; //precfactor of the aperture function
 };
 
 #endif
diff --git a/dune/mmdg/problems/mmdgproblem2.hh b/dune/mmdg/problems/mmdgproblem2.hh
index efe1f3f4e531caa7e1663cf412e5b6fa5fa79549..61624636efc2f67d55c37648f5c237f12aff14a1 100644
--- a/dune/mmdg/problems/mmdgproblem2.hh
+++ b/dune/mmdg/problems/mmdgproblem2.hh
@@ -4,8 +4,8 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem for dim = 2,
-//taken from [Antonietti et al. (2019): Example 6.3]
+//a coupled dg problem with constant aperture
+//taken with adaptions from [Antonietti et al. (2019): Example 6.3]
 template<class Coordinate, class Scalar = double>
 class MMDGProblem2 : public CoupledDGProblem<Coordinate, Scalar>
 {
@@ -21,18 +21,18 @@ public:
   Scalar exactSolution (const Coordinate& pos) const
   {
     Scalar solution =
-      (pos[0] < 0.5) ? std::sin(4 * pos[0]) : std::cos(4 * pos[0]);
-    return solution * std::cos(M_PI * pos[1]);
+      (pos[0] < 0.5) ? sin(4 * pos[0]) : cos(4 * pos[0]);
+    return solution * cos(M_PI * pos[1]);
   }
 
   //the exact solution on the interface at position pos
   Scalar exactInterfaceSolution (const Coordinate& pos) const
   {
-    constexpr Scalar sourcefactor = 0.75 * (std::cos(2.0) + std::sin(2.0));
-    return sourcefactor * std::cos(M_PI * pos[1]);
+    constexpr Scalar solFactor = 0.75 * ( cos(2.0) + sin(2.0) );
+    return solFactor * cos(M_PI * pos[1]);
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
@@ -43,29 +43,29 @@ public:
   {
     constexpr Scalar sourcefactor = 16.0 + M_PI * M_PI;
     Scalar source =
-      (pos[0] < 0.5) ? std::sin(4 * pos[0]) : std::cos(4 * pos[0]);
-    return sourcefactor * source * std::cos(M_PI * pos[1]);
+      (pos[0] < 0.5) ? sin(4 * pos[0]) : cos(4 * pos[0]);
+    return sourcefactor * source * cos(M_PI * pos[1]);
   }
 
   //interface source term at position pos
   Scalar qInterface (const Coordinate& pos) const
   {
-    constexpr Scalar sourcefactor = std::cos(2.0) + std::sin(2.0);
-    return sourcefactor * (4.0 + 0.75 * d_ * d_ * M_PI * M_PI)
-      * std::cos(M_PI * pos[1]);
+    constexpr Scalar sourcefactor = cos(2.0) + sin(2.0);
+    return sourcefactor * ( 4.0 + 0.75 * d_ * d_ * M_PI * M_PI )
+      * cos(M_PI * pos[1]);
   }
 
-  //aperture d of the fracture at position pos
+  //constant aperture d of the fracture
   Scalar aperture (const Coordinate& pos) const
   {
     return d_;
   }
 
-  //permeability per aperture  of the fracture per aperture in normal direction
+  //permeability per aperture of the fracture per aperture in normal direction
   //at position pos
   Scalar Kperp (const Coordinate& pos) const
   {
-    return Scalar(2.0);
+    return 2.0;
   }
 
   //returns the recommended quadrature order to compute an integral
diff --git a/dune/mmdg/problems/mmdgproblem3.hh b/dune/mmdg/problems/mmdgproblem3.hh
index cf7f896a9aa6b61d19dc18a5cecf7d20c9b1b0fa..441aebc2d4ff3ae9b36b3b82a2ba26a47a9da7f2 100644
--- a/dune/mmdg/problems/mmdgproblem3.hh
+++ b/dune/mmdg/problems/mmdgproblem3.hh
@@ -4,8 +4,8 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem for dim = 2,
-//taken from [Antonietti et al. (2019): Example 6.1]
+//a coupled dg problem with constant aperture,
+//taken with adaptions from [Antonietti et al. (2019): Example 6.1]
 template<class Coordinate, class Scalar = double>
 class MMDGProblem3 : public CoupledDGProblem<Coordinate, Scalar>
 {
@@ -21,18 +21,18 @@ public:
   Scalar exactSolution (const Coordinate& pos) const
   {
     Scalar xPlusy = pos[0] + pos[1];
-    Scalar solution = std::exp(xPlusy);
+    Scalar solution = exp(xPlusy);
     return (xPlusy < 1.0) ? solution :
-      0.5 * solution + std::exp(1.0) * (0.5 + 1.5 / sqrt(2.0) * d_);
+      0.5 * solution + exp(1.0) * (0.5 + 1.5 / sqrt(2.0) * d_);
   }
 
   //the exact solution on the interface at position pos
   Scalar exactInterfaceSolution (const Coordinate& pos) const
   {
-    return std::exp(1.0) * ( 1.0 + 1.0 / sqrt(2.0) * d_ );
+    return exp(1.0) * ( 1.0 + 1.0 / sqrt(2.0) * d_ );
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
@@ -42,18 +42,18 @@ public:
   Scalar q (const Coordinate& pos) const
   {
     Scalar xPlusy = pos[0] + pos[1];
-    Scalar source = -std::exp(xPlusy);
+    Scalar source = -exp(xPlusy);
     return (xPlusy < 1.0) ? 2.0 * source : source;
   }
 
   //interface source term at position pos
   Scalar qInterface (const Coordinate& pos) const
   {
-    constexpr Scalar iSource = std::exp(1.0) / sqrt(2.0);
+    constexpr Scalar iSource = exp(1.0) / sqrt(2.0);
     return iSource;
   }
 
-  //aperture d of the fracture at position pos
+  //constant aperture d of the fracture
   Scalar aperture (const Coordinate& pos) const
   {
     return d_;
diff --git a/dune/mmdg/problems/mmdgproblem4.hh b/dune/mmdg/problems/mmdgproblem4.hh
index cf09ef6b727e7b946854d364c29605e582e9b6ba..c8adbfff494997ba68a2cad962f7da6bb05dcb07 100644
--- a/dune/mmdg/problems/mmdgproblem4.hh
+++ b/dune/mmdg/problems/mmdgproblem4.hh
@@ -4,17 +4,24 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem
+//a coupled dg problem wiht non-constant aperture
+//NOTE: To deal with the non-constant aperture, an adaption of the coupled DG
+//      scheme implemented in mmdg.hh is used to solve this problem. Thus, the
+//      interface source term and the tangential permeability per aperture
+//      inside the fracture are multiplied with the aperture function d in
+//      the following problem definition
 template<class Coordinate, class Scalar = double>
 class MMDGProblem4 : public CoupledDGProblem<Coordinate, Scalar>
 {
 public:
   static constexpr int dim = Coordinate::dimension;
+  static constexpr Scalar jump = 1.0; //jump of the pressure at the interface
+
   using Base = CoupledDGProblem<Coordinate, Scalar>;
   using Matrix = typename Base::Matrix;
 
   //constructor
-  MMDGProblem4 (const Scalar d) : d_(d) {}
+  MMDGProblem4 (const Scalar dmax) : d_ (dmax / 1.01) {}
 
   //the exact bulk solution at position pos
   Scalar exactSolution (const Coordinate& pos) const
@@ -23,7 +30,7 @@ public:
 
     if (pos[0] > 0.5)
     {
-      return solution += d_;
+      return solution += jump;
     }
 
     return solution;
@@ -32,41 +39,56 @@ public:
   //the exact solution on the interface at position pos
   Scalar exactInterfaceSolution (const Coordinate& pos) const
   {
-    return 0.25 - pos[1] * pos[1] + 0.5 * d_;
+    return 0.25 - pos[1] * pos[1] + 0.5 * jump;
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
   };
 
   //interface source term at position pos
+  //NOTE: contains an extra factor d
   Scalar qInterface (const Coordinate& pos) const
   {
-    return 2.0 * d_;
+    const Scalar d = aperture(pos);
+    const Scalar dPrime = sqrt(gradAperture(pos) * gradAperture(pos));
+    const Scalar dPrimePrime = 2.0 * d_;
+
+    return d * ( -( dPrime * dPrime + d * dPrimePrime ) *
+      exactInterfaceSolution(pos) + 2.0 * d * ( 3.0 * pos[1] * dPrime + d ) );
   }
 
   //aperture d of the fracture at position pos
   Scalar aperture (const Coordinate& pos) const
   {
-    return d_;
+    return d_ * ( pos[1] * pos[1] + 0.01 );
+  }
+
+  //tangential gradient of the aperture d of the fracture at position pos
+  Coordinate gradAperture (const Coordinate& pos) const
+  {
+    Coordinate gradD(0.0);
+    gradD[1] = 2.0 * d_ * pos[1];
+    return gradD;
   }
 
   //permeability of the fracture in normal direction at position pos
   Scalar Kperp (const Coordinate& pos) const
   {
-    return Scalar(1.0) / d_;
+    return 1.0 / jump;
   }
 
   //tangential permeability tensor of the interface at position pos
+  //NOTE: contains an extra factor d
   Matrix Kparallel (const Coordinate& pos) const
   {
     Matrix permeability(0.0);
 
     for (int i = 0; i < dim; i++)
     {
-      permeability[i][i] = 1.0 / d_;
+      permeability[i][i] = aperture(pos);
     }
 
     return permeability;
@@ -79,13 +101,30 @@ public:
     return 3;
   }
 
+  //returns the recommended quadrature order to compute an integral
+  //over x * qInterface(x)
+  int quadratureOrder_qInterface () const
+  {
+    return 7;
+  }
+
   //returns the recommended quadrature order to compute an integral
   //over  x * d^2 * interfaceBoundary(x)
   //and   x * d * interfaceBoundary(x) * (Kpar * grad(d))
   //and   d^2 * interfaceBoundary(x) * Kpar
   int quadratureOrderInterfaceBoundary () const
   {
-    return 3;
+    return 8;
+  }
+
+  //returns the recommended quadrature order to compute integrals
+  //over  x^2 * (Kpar * grad(d) * grad(d))
+  //and   x^2 * d^2
+  //and   x^2 * d * (Kpar * grad(d))
+  //and   x * d^2 * Kpar
+  int quadratureOrder_Kparallel () const
+  {
+    return 7;
   }
 
 private:
diff --git a/dune/mmdg/problems/mmdgproblem5.hh b/dune/mmdg/problems/mmdgproblem5.hh
index ee614898bdfdaadf48f5e3b1e97aa5986101799d..7b276a0e37a5864b802c7a67252cdaccdc590eb9 100644
--- a/dune/mmdg/problems/mmdgproblem5.hh
+++ b/dune/mmdg/problems/mmdgproblem5.hh
@@ -4,7 +4,7 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem
+//a coupled dg problem with constant aperture
 template<class Coordinate, class Scalar = double>
 class MMDGProblem5 : public CoupledDGProblem<Coordinate, Scalar>
 {
@@ -29,7 +29,7 @@ public:
     return 0.5 / (1.0 + pos[1] * pos[1]);
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
@@ -51,7 +51,7 @@ public:
     return 0.5 * d_ * d_ - 2.0 * sqrt(2.0) / (1.0 + pos[1] * pos[1]);
   }
 
-  //aperture d of the fracture at position pos
+  //constant aperture d of the fracture
   Scalar aperture (const Coordinate& pos) const
   {
     return d_;
diff --git a/dune/mmdg/problems/mmdgproblem6.hh b/dune/mmdg/problems/mmdgproblem6.hh
index 311042544d461531f0bdf64b144b02d35dfcfa04..90d267497bc2170f5499ba26a83921a6380b22d4 100644
--- a/dune/mmdg/problems/mmdgproblem6.hh
+++ b/dune/mmdg/problems/mmdgproblem6.hh
@@ -4,18 +4,26 @@
 #include <cmath>
 #include <dune/mmdg/problems/coupleddgproblem.hh>
 
-//a coupled dg problem
+//a coupled dg problem with non-constant exponentially-shaped aperture
+//with exact solution for arbitrary coupling constant xi > 0.5
+//NOTE: To deal with the non-constant aperture, an adaption of the coupled DG
+//      scheme implemented in mmdg.hh is used to solve this problem. Thus, the
+//      interface source term and the tangential permeability per aperture
+//      inside the fracture are multiplied with the aperture function d in
+//      the following problem definition
 template<class Coordinate, class Scalar = double>
 class MMDGProblem6 : public CoupledDGProblem<Coordinate, Scalar>
 {
 public:
   static constexpr int dim = Coordinate::dimension;
+  using Base = CoupledDGProblem<Coordinate, Scalar>;
+  using Matrix = typename Base::Matrix;
 
-  //constructor
-  MMDGProblem6 (const Scalar d0) : d0_(d0), xi_(1.0) {}
+  //constructor with default coupling parameter xi = 1.0
+  MMDGProblem6 (const Scalar dmax) : dmax_(dmax), xi_(1.0) {}
 
-  //constructor
-  MMDGProblem6 (const Scalar d0, const Scalar xi) : d0_(d0), xi_(xi) {}
+  //constructor with arbitrary coupling parameter xi
+  MMDGProblem6 (const Scalar dmax, const Scalar xi) : dmax_(dmax), xi_(xi) {}
 
   //the exact bulk solution at position pos
   Scalar exactSolution (const Coordinate& pos) const
@@ -23,20 +31,20 @@ public:
     Scalar xArg = (pos[0] < 0.5) ? sqrt(2.0) * (2.0 * pos[0] - 1.0)
       : sqrt(2.0) * (2.0 * pos[0] + 1.0);
 
-    return std::cos(4.0 * pos[1]) * std::cosh(xArg);
+    return cos(4.0 * pos[1]) * cosh(xArg);
   }
 
   //the exact solution on the interface at position pos
   Scalar exactInterfaceSolution (const Coordinate& pos) const
   {
-    constexpr Scalar coshsqrt2 = std::cosh(sqrt(2.0));
-    constexpr Scalar sinhsqrt2 = std::sinh(sqrt(2.0));
+    constexpr Scalar coshsqrt2 = cosh(sqrt(2.0));
+    constexpr Scalar sinhsqrt2 = sinh(sqrt(2.0));
 
-    return std::cos(4.0 * pos[1]) * (coshsqrt2 * coshsqrt2
-      - (2 * xi_ - 1) * sinhsqrt2 * sinhsqrt2);
+    return cos(4.0 * pos[1]) * ( coshsqrt2 * coshsqrt2
+      - ( 2 * xi_ - 1 ) * sinhsqrt2 * sinhsqrt2 );
   }
 
-  //indicates whether an exact solution is implemented for the problem
+  //exact solution is implemented
   bool hasExactSolution () const
   {
     return true;
@@ -48,34 +56,36 @@ public:
     Scalar xArg = (pos[0] < 0.5) ? sqrt(2.0) * (2.0 * pos[0] - 1.0)
       : sqrt(2.0) * (2.0 * pos[0] + 1.0);
 
-    return 8.0 * std::cos(4.0 * pos[1]) * std::cosh(xArg);
+    return 8.0 * cos(4.0 * pos[1]) * cosh(xArg);
   }
 
   //interface source term at position pos
+  //NOTE: contains an extra factor d
   Scalar qInterface (const Coordinate& pos) const
   {
-    const Scalar cos4y = std::cos(4.0 * pos[1]);
+    const Scalar cos4y = cos(4.0 * pos[1]);
     constexpr Scalar sqrt2 = 2.0 * sqrt(2.0);
-    constexpr Scalar coshsqrt2 = std::cosh(sqrt(2.0));
-    constexpr Scalar sinhsqrt2 = std::sinh(sqrt(2.0));
+    constexpr Scalar coshsqrt2 = cosh(sqrt(2.0));
+    constexpr Scalar sinhsqrt2 = sinh(sqrt(2.0));
     const Scalar hyperbolicFactor =
       (coshsqrt2 * coshsqrt2 - (2 * xi_ - 1) * sinhsqrt2 * sinhsqrt2);
 
-    return -16.0 * d0_ * d0_ * std::exp(-8.0 * pos[1]) * hyperbolicFactor * ( 
-      cos4y + 3.0 * std::sin(4.0 * pos[1]) ) - sqrt2 * std::sinh(sqrt2) * cos4y;
+    return -16.0 * aperture(pos) * dmax_ * dmax_ * exp(-8.0 * pos[1]) *
+      hyperbolicFactor * ( cos4y + 3.0 * sin(4.0 * pos[1]) )
+      - sqrt2 * sinh(sqrt2) * cos4y;
   }
 
   //aperture d of the fracture at position pos
   Scalar aperture (const Coordinate& pos) const
   {
-    return d0_ * std::exp(-4.0 * pos[1]);
+    return dmax_ * exp(-4.0 * pos[1]);
   }
 
   //tangential gradient of the aperture d of the fracture at position pos
   Coordinate gradAperture (const Coordinate& pos) const
   {
     Coordinate gradD(0.0);
-    gradD[1] = -4.0 * d0_ * std::exp(-4.0 * pos[1]);
+    gradD[1] = -4.0 * dmax_ * exp(-4.0 * pos[1]);
     return gradD;
   }
 
@@ -83,7 +93,21 @@ public:
   //at position pos
   Scalar Kperp (const Coordinate& pos) const
   {
-    return sqrt(2.0) / std::tanh(sqrt(2.0));
+    return sqrt(2.0) / tanh(sqrt(2.0));
+  }
+
+  //tangential permeability tensor of the interface at position pos
+  //NOTE: contains an extra factor d
+  Matrix Kparallel (const Coordinate& pos) const
+  {
+    Matrix permeability(0.0);
+
+    for (int i = 0; i < dim; i++)
+    {
+      permeability[i][i] = aperture(pos);
+    }
+
+    return permeability;
   }
 
   //returns the recommended quadrature order to compute an integral
@@ -127,7 +151,7 @@ public:
   }
 
 private:
-  Scalar d0_; //prefactor of the aperture
+  Scalar dmax_; //maximum aperture
   Scalar xi_; //coupling constant
 
 };
diff --git a/dune/mmdg/problems/mmdgproblem7.hh b/dune/mmdg/problems/mmdgproblem7.hh
new file mode 100644
index 0000000000000000000000000000000000000000..b0a606327bb2765ea3858f5a0943d9f8886731f6
--- /dev/null
+++ b/dune/mmdg/problems/mmdgproblem7.hh
@@ -0,0 +1,216 @@
+#ifndef __DUNE_MMDG_MMDGPROBLEM7_HH__
+#define __DUNE_MMDG_MMDGPROBLEM7_HH__
+
+#include <cmath>
+#include <dune/mmdg/problems/coupleddgproblem.hh>
+
+//coupled dg problem with non constant cosine-shaped fracture,
+//this is the averaged problem corresponding to the fully resolved problem dg4
+//NOTE: The "exact" solution of the averaged problem that is implemented below
+//      does not solve the reduced problem. Thus, there is no convergence for
+//      this problem.
+//NOTE: To deal with the non-constant aperture, an adaption of the coupled DG
+//      scheme implemented in mmdg.hh is used to solve this problem. Thus, the
+//      interface source term and the tangential permeability per aperture
+//      inside the fracture are multiplied with the aperture function d in
+//      the following problem definition
+template<class Coordinate, class Scalar = double>
+class MMDGProblem7 : public CoupledDGProblem<Coordinate, Scalar>
+{
+public:
+  static constexpr int dim = Coordinate::dimension;
+  using Base = CoupledDGProblem<Coordinate, Scalar>;
+  using Matrix = typename Base::Matrix;
+
+  //constructor
+  MMDGProblem7 (const Scalar dmin, const Scalar dmax)
+    : dmin_(dmin), dmax_(dmax) {}
+
+  //the exact bulk solution at position pos
+  Scalar exactSolution (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+
+    if ( pos[0] < 0.5 )
+    { //pos in Omega_1 (left of the fracture)
+      return 2.0 * ( pos[0] + d ) * exp(-d);
+    }
+
+    //pos in Omega_2 (right of the fracture)
+    return 2.0 * pos[0] * exp(d);
+  }
+
+  //the exact solution on the interface at position pos
+  //NOTE: this is the averaged pressure form problem dg4 but not an exact
+  //      solution of the system with reduced fracture
+  Scalar exactInterfaceSolution (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+    return ( 1.0 + d ) / d * sinh(d);
+  }
+
+  //exact solution is implemented
+  bool hasExactSolution () const
+  {
+    return true;
+  };
+
+  //source term at position pos
+  Scalar q (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+    const Scalar dPrime2 = gradAperture(pos) * gradAperture(pos);
+    const Scalar dPrimePrime = aperturePrimePrime(pos);
+
+    if ( pos[0] < 0.5 )
+    { //pos in Omega_1 (left of the fracture)
+      return -2.0 * exp(-d) / ( 1.0 - d ) * ( ( 1.0 - pos[0] - d )
+        * ( dPrimePrime + dPrime2 * d / ( 1.0 - d ) ) - dPrime2 );
+    }
+
+    //pos in Omega_2 (right of the fracture)
+    return -2.0 * pos[0] * exp(d) / ( 1.0 + d )
+      * ( dPrimePrime + dPrime2 * d / ( 1.0 + d ) );
+  }
+
+  //interface source term at position pos
+  //NOTE: contains an extra factor d
+  Scalar qInterface (const Coordinate& pos) const
+  {
+    return -( 4.0 + aperturePrimePrime(pos) ) * sinh(aperture(pos))
+      * aperture(pos);
+  }
+
+  //aperture d of the fracture at position pos
+  Scalar aperture (const Coordinate& pos) const
+  {
+    return dmin_ + 0.5 * ( dmax_ - dmin_ ) * ( 1.0 + cos(8.0 * M_PI * pos[1]) );
+  }
+
+  //tangential gradient of the aperture d of the fracture at position pos
+  Coordinate gradAperture (const Coordinate& pos) const
+  {
+    Coordinate gradD(0.0);
+    gradD[1] = -4.0 * M_PI * ( dmax_ - dmin_ ) * sin(8.0 * M_PI * pos[1]);
+    return gradD;
+  }
+
+  //bulk permeability tensor at position pos
+  Matrix K (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+
+    Matrix permeability(0.0);
+
+    if ( pos[0] < 0.5 )
+    { //pos in Omega_1 (left of the fracture)
+      permeability[0][0] = 1.0;
+
+      for (int i = 1; i < dim; i++)
+      {
+        permeability[i][i] = 1.0 / ( 1.0 - d );
+      }
+    }
+    else
+    { //pos in Omega_2 (right of the fracture)
+      permeability[0][0] = 1.0;
+
+      for (int i = 1; i < dim; i++)
+      {
+        permeability[i][i] = 1.0 / ( 1.0 + d );
+      }
+    }
+
+    return permeability;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over an entry K[i][j] of the permeability tensor
+  int quadratureOrder_K () const
+  {
+    return 10;
+  }
+
+  //permeability per aperture of the fracture in normal direction
+  //at position pos
+  Scalar Kperp (const Coordinate& pos) const
+  {
+    const Scalar d = aperture(pos);
+
+    return 1.0 / ( d * ( 1.0 + d ) );
+  }
+
+  //tangential permeability tensor of the interface at position pos
+  //NOTE: contains an extra factor d
+  Matrix Kparallel (const Coordinate& pos) const
+  {
+    Matrix permeability(0.0);
+
+    for (int i = 0; i < dim; i++)
+    {
+      permeability[i][i] = 1.0;
+    }
+
+    return permeability;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over x * boundary(x)
+  int quadratureOrderBoundary () const
+  {
+    return 10;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over  x * d^2 * interfaceBoundary(x)
+  //and   x * d * interfaceBoundary(x) * (Kpar * grad(d))
+  //and   d^2 * interfaceBoundary(x) * Kpar
+  int quadratureOrderInterfaceBoundary () const
+  {
+    return 10;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over x * qInterface(x)
+  int quadratureOrder_qInterface () const
+  {
+    return 10;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over x * q(x)
+  int quadratureOrder_q () const
+  {
+    return 10;
+  }
+
+  //returns the recommended quadrature order to compute integrals
+  //over  x^2 * (Kpar * grad(d) * grad(d))
+  //and   x^2 * d^2
+  //and   x^2 * d * (Kpar * grad(d))
+  //and   x * d^2 * Kpar
+  int quadratureOrder_Kparallel () const
+  {
+    return 10;
+  }
+
+  //returns the recommended quadrature order to compute an integral
+  //over x * Kperp(x)
+  int quadratureOrder_Kperp () const
+  {
+    return 10;
+  }
+
+private:
+  //second derivative of aperture at position pos
+  const Scalar aperturePrimePrime (const Coordinate& pos) const
+  {
+    return -32.0 * M_PI * M_PI * ( dmax_ - dmin_ ) * cos(8.0 * M_PI * pos[1]);
+  }
+
+  const Scalar dmin_; //minimum aperture of the fracture
+  const Scalar dmax_; //maximum aperture of the fracture
+
+};
+
+#endif
diff --git a/dune/mmdg/solvertype.hh b/dune/mmdg/solvertype.hh
new file mode 100644
index 0000000000000000000000000000000000000000..6ca83002e71a6f558eeab4ad7036f14ab47a2eb1
--- /dev/null
+++ b/dune/mmdg/solvertype.hh
@@ -0,0 +1,6 @@
+//determines the type of solver that is applied to a system of linear equations
+enum SolverType
+{
+  Cholmod,
+  UMFPack
+};
diff --git a/src/dg.cc b/src/dg.cc
index 2dedbca292ccc37ac5a9b0d35be06b423aaf1221..d78f919e8e8cfd963f8f135f5da4efe5079b38fd 100644
--- a/src/dg.cc
+++ b/src/dg.cc
@@ -12,9 +12,8 @@
 #include <dune/common/parametertreeparser.hh>
 
 #include <dune/grid/common/mcmgmapper.hh>
-#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
-#include <dune/grid/io/file/dgfparser/dgfug.hh>
-#include <dune/grid/yaspgrid.hh>
+#include <dune/grid/onedgrid.hh>
+#include <dune/grid/io/file/dgfparser/dgfoned.hh>
 
 #include <dune/mmesh/mmesh.hh>
 
@@ -24,6 +23,8 @@
 #include <dune/mmdg/problems/dgproblem1.hh>
 #include <dune/mmdg/problems/dgproblem2.hh>
 #include <dune/mmdg/problems/dgproblem3.hh>
+#include <dune/mmdg/problems/dgproblem4.hh>
+#include <dune/mmdg/problems/dgproblem5.hh>
 
 int main(int argc, char** argv)
 {
@@ -36,8 +37,8 @@ int main(int argc, char** argv)
 
     static constexpr int dim = GRIDDIM;
 
-    //use YaspGrid if dim = 1 and MMesh otherwise
-    using Grid = std::conditional<dim == 1, Dune::YaspGrid<dim>,
+    //use OneDGrid if dim = 1 and MMesh otherwise
+    using Grid = std::conditional<dim == 1, Dune::OneDGrid,
       Dune::MovingMesh<dim>>::type;
     using GridFactory = Dune::DGFGridFactory<Grid>;
     using GridView = typename Grid::LeafGridView;
@@ -52,12 +53,21 @@ int main(int argc, char** argv)
     Dune::ParameterTree pt;
     Dune::ParameterTreeParser::readINITree("parameterDG.ini", pt);
 
-    //assume constant penalty parameter
-    const double mu0 = std::stod(pt["mu0"]);
+    double mu0; //penalty parameter (prefactor)
+
+    try
+    {
+      mu0 = std::stod(pt["mu0"]);
+    }
+    catch (std::exception& e)
+    {
+      DUNE_THROW(Dune::Exception,
+        "Invalid penalty parameter or parameter 'mu0' not specified in the "
+        "file parameterDG.ini");
+    }
 
     //create a grid from .dgf file
     GridFactory gridFactory( "grids/cube" + std::to_string(dim) + "d.dgf" );
-
     const Grid& grid = *gridFactory.grid();
     const GridView& gridView = grid.leafGridView();
 
@@ -87,13 +97,63 @@ int main(int argc, char** argv)
     }
     else
     {
-      DUNE_THROW(Dune::Exception,
-        "Invalid problem type or parameter 'problem' not specified in file "
-        "parameterDG.ini (use 'dg1' to 'dg3')");
+      double dmin; //minimum aperture
+      double dmax; //maximum aperture
+
+      try
+      {
+        dmin = std::stod(pt["dmin"]);
+        dmax = std::stod(pt["dmax"]);
+      }
+      catch (std::exception& e)
+      {
+        DUNE_THROW(Dune::Exception,
+          "The problems dg4 and dg5 require the parameters 'dmin' and 'dmax'. "
+          "Check the file parameterDG.ini and make sure that they are "
+          "specified correctly.");
+      }
+
+      if (pt["problem"] == "dg4")
+      {
+        problem = new DGProblem4<Coordinate>(dmin, dmax);
+      }
+      else if (pt["problem"] == "dg5")
+      {
+        problem = new DGProblem5<Coordinate>(dmin, dmax);
+
+        std::cout << "NOTE: You will not see convergence for problem dg5 as it"
+          " only fulfills continuity of the normal component of the Darcy "
+          "velocity with respect to the normal of the hyperplane Gamma = "
+          "{ x_1 = 0.5 } but not with respect to the normal of the actual "
+          "interfaces between the bulk and fracture domains. \n\n";
+      }
+      else
+      {
+        DUNE_THROW(Dune::Exception,
+          "Invalid problem type or parameter 'problem' not specified in file "
+          "parameterDG.ini (use 'dg1' to 'dg5')");
+      }
     }
 
-    DG dg(gridView, mapper, *problem);
+    //determine solver type
+    SolverType solver = SolverType::Cholmod;
+
+    if (pt.hasKey("solver"))
+    {
+      if (pt["solver"] == "UMFPack")
+      {
+        solver = SolverType::UMFPack;
+      }
+      else if (pt["solver"] != "Cholmod")
+      {
+        DUNE_THROW(Dune::Exception,
+          "Invalid solver type (use 'Cholmod' or 'UMFPack' for the parameter "
+          "'solver' in the file parameterDG.ini)");
+      }
+    }
 
+    //apply DG scheme
+    DG dg(gridView, mapper, *problem, solver);
     dg(mu0);
 
     //error and total run time
@@ -107,7 +167,7 @@ int main(int argc, char** argv)
       largestEdgeLength = std::max(largestEdgeLength, edge.geometry().volume());
     }
 
-    //write error, runtime and maximum edge length
+    //write error, runtime and maximum edge length to file
     std::ofstream errorFile("convergenceData", std::ios::out | std::ios::trunc);
 
     if (errorFile.is_open())
diff --git a/src/dgAnalysis.py b/src/dgAnalysis.py
index 4a6edd2bc48ce20c9aca62c095e5137798e42c4b..a54c24d9871000717ffbf7360a502b8b15b829d1 100644
--- a/src/dgAnalysis.py
+++ b/src/dgAnalysis.py
@@ -47,22 +47,26 @@ def readData():
     return np.array([error, timeTotal, numberOfElements])
 
 
-# determines the parameter "fastEOC" from the ini file
-def determineFastEOC ():
+# determines the problem type and the parameter "fastEOC" from the ini file
+def getProblemType ():
+    # storage for problem type (1 to 5)
+    problemType = None
+
     # boolean that determines whether to exclude computationally expensive grids
     fastEOC = False
 
-    # read ini file content
+    # read file content and get problem type
     with open("parameterDG.ini", "r") as file:
         lines = file.read().splitlines()
 
         for i in range(len(lines)):
-            if (lines[i].startswith("fastEOC") and \
+            if (lines[i].startswith("problem")):
+                problemType = int(lines[i].rstrip()[-1])
+            elif (lines[i].startswith("fastEOC") and \
              lines[i].rstrip().lower().endswith("true")):
                 fastEOC = True
-                break
 
-    return fastEOC
+    return problemType, fastEOC
 
 
 # === main ===
@@ -78,13 +82,21 @@ numberOfMeans = 1
 numElemsPerDir_12 = np.unique(np.logspace(0, 2.7, 15).astype(int))
 numElemsPerDir_3 = np.unique(np.logspace(0, 1.5, 8).astype(int))
 
-if determineFastEOC(): # exclude computationally expensive grids
+# get problem type (integer from 1 to 5) from ini file
+problemType, fastEOC = getProblemType()
+
+if fastEOC: # exclude computationally expensive grids
     numElemsPerDir_12 = numElemsPerDir_12[:-3]
     numElemsPerDir_3 = numElemsPerDir_3[:-2]
 else:
     print("fastEOC = false. This may take some minutes.\n")
 
-for dim in [1, 2, 3]:
+dimensions = [1, 2, 3]
+
+if problemType in [4, 5]:
+    dimensions = [2, 3]
+
+for dim in dimensions:
 
     numElemsPerDir = numElemsPerDir_3 if (dim == 3) else numElemsPerDir_12
 
diff --git a/src/mmdg.cc b/src/mmdg.cc
index 7a2bca12179fef4e816757b7f015b7776fc5d5c0..6897c0d2304293067cb869aaa76407f06a54450a 100644
--- a/src/mmdg.cc
+++ b/src/mmdg.cc
@@ -26,6 +26,7 @@
 #include <dune/mmdg/problems/mmdgproblem4.hh>
 #include <dune/mmdg/problems/mmdgproblem5.hh>
 #include <dune/mmdg/problems/mmdgproblem6.hh>
+#include <dune/mmdg/problems/mmdgproblem7.hh>
 
 int main(int argc, char** argv)
 {
@@ -56,56 +57,97 @@ int main(int argc, char** argv)
     Dune::ParameterTree pt;
     Dune::ParameterTreeParser::readINITree("parameterMMDG.ini", pt);
 
-    const double mu0 = std::stod(pt["mu0"]); //penalty parameter (prefactor)
-    const double aperture = std::stod(pt["d"]); //aperture (prefactor)
+    double mu0; //penalty parameter (prefactor)
+    double dmax; //maximum aperture
     double xi; //coupling parameter
 
+    try
+    {
+      mu0 = std::stod(pt["mu0"]);
+    }
+    catch (std::exception& e)
+    {
+      DUNE_THROW(Dune::Exception,
+        "Invalid penalty parameter or parameter 'mu0' not specified in the "
+        "file parameterDG.ini");
+    }
+
+    try
+    {
+      dmax = std::stod(pt["dmax"]);
+    }
+    catch (std::exception& e)
+    {
+      DUNE_THROW(Dune::Exception,
+        "Invalid maximum aperture or parameter 'dmax' not specified in the "
+        "file parameterDG.ini");
+    }
+
     Problem* problem; //problem to be solved
 
-    std::string gridType;
+    std::string gridType; //prefix of the grid file name
 
     //determine problem type
     if (pt["problem"] == "mmdg1")
     {
-      problem = new MMDGProblem1<Coordinate>(aperture);
+      problem = new MMDGProblem1<Coordinate>(dmax);
       gridType = "mmdg2_C";
       xi = 0.75;
     }
     else if (pt["problem"] == "mmdg2")
     {
-      problem = new MMDGProblem2<Coordinate>(aperture);
+      problem = new MMDGProblem2<Coordinate>(dmax);
       gridType = "mmdg2_C";
       xi = 0.75;
     }
     else if (pt["problem"] == "mmdg3")
     {
-      problem = new MMDGProblem3<Coordinate>(aperture);
+      problem = new MMDGProblem3<Coordinate>(dmax);
       gridType = "mmdg3_C";
       xi = 1.0;
     }
     else if (pt["problem"] == "mmdg4")
     {
-      problem = new MMDGProblem4<Coordinate>(aperture);
+      problem = new MMDGProblem4<Coordinate>(dmax);
       gridType = "mmdg2_C";
       xi = 0.75;
     }
     else if (pt["problem"] == "mmdg5")
     {
-      problem = new MMDGProblem5<Coordinate>(aperture);
+      problem = new MMDGProblem5<Coordinate>(dmax);
       gridType = "mmdg5_C";
       xi = 0.75;
     }
     else if (pt["problem"] == "mmdg6")
     {
       xi = (pt.hasKey("xi")) ? std::stod(pt["xi"]) : 1.0;
-      problem = new MMDGProblem6<Coordinate>(aperture, xi);
+      problem = new MMDGProblem6<Coordinate>(dmax, xi);
+      gridType = "mmdg2_C";
+    }
+    else if (pt["problem"] == "mmdg7")
+    {
+      double dmin; //minimum aperture
+
+      try
+      {
+        dmin = std::stod(pt["dmin"]);
+      }
+      catch (std::exception& e)
+      {
+        DUNE_THROW(Dune::Exception,
+          "Problem dg4 requires the parameter 'dmin'. Check the "
+          "file parameterMMDG.ini and make sure that it is specified.");
+      }
+
+      problem = new MMDGProblem7<Coordinate>(dmin, dmax);
       gridType = "mmdg2_C";
+      xi = 0.75;
     }
     else
     {
       DUNE_THROW(Dune::Exception,
         "Invalid problem type or parameter 'problem' not specified in file "
-        "parameterDG.ini (use 'mmdg1' to 'mmdg6')");
+        "parameterDG.ini (use 'mmdg1' to 'mmdg7')");
     }
 
     if (pt.hasKey("gridfile")) //non-default grid type
@@ -118,7 +160,24 @@ int main(int argc, char** argv)
       xi = std::stod(pt["xi"]);
     }
 
-    //create a grid from .dgf file
+    //determine solver type
+    SolverType solver = SolverType::Cholmod;
+
+    if (pt.hasKey("solver"))
+    {
+      if (pt["solver"] == "UMFPack")
+      {
+        solver = SolverType::UMFPack;
+      }
+      else if (pt["solver"] != "Cholmod")
+      {
+        DUNE_THROW(Dune::Exception,
+          "Invalid solver type (use 'Cholmod' or 'UMFPack' for the parameter "
+          "'solver' in the file parameterDG.ini)");
+      }
+    }
+
+    //create the grid from the .msh file
     GridFactory gridFactory( "grids/" + gridType + "_" + std::to_string(dim)
       + "d.msh" );
     const Grid& grid = *gridFactory.grid();
@@ -130,7 +189,8 @@ int main(int argc, char** argv)
     const Mapper mapper(gridView, Dune::mcmgElementLayout());
     const IMapper iMapper(iGridView, Dune::mcmgElementLayout());
 
-    MMDG mmdg(gridView, mapper, iGridView, iMapper, *problem);
+    //apply the coupled DG scheme
+    MMDG mmdg(gridView, mapper, iGridView, iMapper, *problem, solver);
     mmdg(mu0, xi);
 
     //errors and total run time
diff --git a/src/mmdgAnalysis.py b/src/mmdgAnalysis.py
index 4aecbc6a4113f44c9c0a66fba986f37334ebcd90..5ca18824b79ef9b8b4f346856e272cbde8946408 100644
--- a/src/mmdgAnalysis.py
+++ b/src/mmdgAnalysis.py
@@ -57,7 +57,7 @@ def readData():
 
 # determines the problem type and the parameter "fastEOC" from the ini file
 def getProblemType ():
-    # storage for problem type (1 to 6)
+    # storage for problem type (1 to 7)
     problemType = None
 
     # boolean that determines whether to exclude computationally expensive grids
@@ -113,7 +113,7 @@ gridfiles_3d = ["A", "B", "C", "D", "E", "F", "G"]
 # get problem type (integer from 1 to 6) from ini file
 problemType, fastEOC = getProblemType()
 
-if problemType in [1, 4, 6]: # these problems use the same grids
+if problemType in [1, 4, 6, 7]: # these problems use the same grids
     problemType = 2
 
 if fastEOC: # exclude computationally expensive grids
diff --git a/src/parameterDG.ini b/src/parameterDG.ini
index 275babcaa75b797c5558068c7a394eb716598827..c7ee27f47aab88515617404f860f61d66f9e2618 100644
--- a/src/parameterDG.ini
+++ b/src/parameterDG.ini
@@ -1,3 +1,6 @@
 mu0 = 1000
-problem = dg2
+problem = dg4
+dmax = 1e-1
+dmin = 1e-2
+solver = Cholmod
 fastEOC = true
diff --git a/src/parameterMMDG.ini b/src/parameterMMDG.ini
index 257871d69143b4d3315df49397f181c785ad5fab..f572d82a712d1c711ad7a6b727344ab9b9723f50 100644
--- a/src/parameterMMDG.ini
+++ b/src/parameterMMDG.ini
@@ -1,6 +1,8 @@
 mu0 = 1000
-problem = mmdg2
-d = 1e-2
+problem = mmdg6
+dmax = 1e-3
+dmin = 1e-2
 #xi = 0.75
 gridfile = mmdg2_C
+solver = Cholmod
 fastEOC = true
diff --git a/src/plotDG.py b/src/plotDG.py
index dbbed59eac9b5503802f0b16e6d93c287bfe3bbb..5bfaf15154960f4c933c3db701a9ee26d8fda828 100644
--- a/src/plotDG.py
+++ b/src/plotDG.py
@@ -3,6 +3,22 @@ import matplotlib.pyplot as plt
 from mpltools.annotation import slope_marker
 import matplotlib.pylab as pylab
 
+# determines the problem type from the ini file
+def getProblemType ():
+    # storage for problem type (1 to 5)
+    problemType = None
+
+    # read file content and get problem type
+    with open("parameterDG.ini", "r") as file:
+        lines = file.read().splitlines()
+
+        for i in range(len(lines)):
+            if (lines[i].startswith("problem")):
+                problemType = int(lines[i].rstrip()[-1])
+
+    return problemType
+
+
 params = {'legend.fontsize': 'x-large',
          'axes.labelsize': 'x-large',
          'axes.titlesize':'x-large',
@@ -10,17 +26,24 @@ params = {'legend.fontsize': 'x-large',
          'ytick.labelsize':'x-large'}
 pylab.rcParams.update(params)
 
-data_1d = np.loadtxt("plots/dgAnalysis_1d")
+problemType = getProblemType()
+
+data_1d = None
 data_2d = np.loadtxt("plots/dgAnalysis_2d")
 data_3d = np.loadtxt("plots/dgAnalysis_3d")
 
-plt.loglog(np.reciprocal(data_1d[:,2]), data_1d[:,0], 'g^-', label='$n=1$')
+if problemType in [1,2,3]:
+    data_1d = np.loadtxt("plots/dgAnalysis_1d")
+    plt.loglog(np.reciprocal(data_1d[:,2]), data_1d[:,0], 'g^-', label='$n=1$')
+
 plt.loglog(np.reciprocal(data_2d[:,2]), data_2d[:,0], 'bo-', label='$n=2$')
 plt.loglog(np.reciprocal(data_3d[:,2]), data_3d[:,0], 'rs-', label='$n=3$')
 
+slopeSize = 0.15 if problemType in [1,2,3] else 0.075
 x = 1.0 / data_3d[3,2]
-y = 10 ** (0.2 * np.log10(data_3d[3,0]) + 0.8 * np.log10(data_3d[4,0]))
-slope_marker((x, y), -2, size_frac = 0.15, invert = True, pad_frac = 0.12, \
+y = 10 ** (0.1 * np.log10(data_3d[3,0]) + 0.9 * np.log10(data_3d[4,0]))
+
+slope_marker((x, y), -2, size_frac = slopeSize, invert = True, pad_frac = 0.12,\
     poly_kwargs={'ec': 'black', 'fill': False}, \
     text_kwargs={'size': 'x-large', 'text': '2', 'usetex': True})
 plt.xlabel('$h^{-1}$')
diff --git a/src/plotMMDG.py b/src/plotMMDG.py
index 40a6e68899afebaf702e069f05d59e7dd0b0dd9a..f4f67c35698160d55c07560ab47e894cf5cf205f 100644
--- a/src/plotMMDG.py
+++ b/src/plotMMDG.py
@@ -3,6 +3,23 @@ import matplotlib.pyplot as plt
 from mpltools.annotation import slope_marker
 import matplotlib.pylab as pylab
 
+
+# determines the problem type from the ini file
+def getProblemType ():
+    # storage for problem type (1 to 7)
+    problemType = None
+
+    # read file content and get problem type
+    with open("parameterMMDG.ini", "r") as file:
+        lines = file.read().splitlines()
+
+        for i in range(len(lines)):
+            if (lines[i].startswith("problem")):
+                problemType = int(lines[i].rstrip()[-1])
+
+    return problemType
+
+
 params = {'legend.fontsize': 'x-large',
          'axes.labelsize': 'x-large',
          'axes.titlesize':'x-large',
@@ -13,6 +30,8 @@ pylab.rcParams.update(params)
 data_2d = np.loadtxt("plots/mmdgAnalysis_2d")
 data_3d = np.loadtxt("plots/mmdgAnalysis_3d")
 
+problemType = getProblemType()
+
 # plot total error
 plt.figure()
 plt.loglog(np.reciprocal(np.maximum(data_2d[:,3], data_2d[:,4])), data_2d[:,2],\
@@ -20,7 +39,7 @@ plt.loglog(np.reciprocal(np.maximum(data_2d[:,3], data_2d[:,4])), data_2d[:,2],\
 plt.loglog(np.reciprocal(np.maximum(data_3d[:,3], data_3d[:,4])), data_3d[:,2],\
     'rs-', label='$n=3$')
 
-if data_3d[0,2] > data_3d[-1,2]:
+if data_3d[0,2] > data_3d[-1,2] and problemType not in [1,7]:
     x = 1.0 / np.maximum(data_3d[3,3], data_3d[3,4])
     y = 10 ** (0.2 * np.log10(data_3d[3,2]) + 0.8 * np.log10(data_3d[4,2]))
     slope_marker((x,y), -2, size_frac = 0.15, invert = True, pad_frac = 0.12, \
@@ -38,7 +57,7 @@ plt.figure()
 plt.loglog(np.reciprocal(data_2d[:,3]), data_2d[:,0], 'bo-', label='$n=2$')
 plt.loglog(np.reciprocal(data_3d[:,3]), data_3d[:,0], 'rs-', label='$n=3$')
 
-if data_3d[0,0] > data_3d[-1,0]:
+if data_3d[0,0] > data_3d[-1,0] and problemType not in [1,7]:
     x = 1.0 / data_3d[3,3]
     y = 10 ** (0.2 * np.log10(data_3d[3,0]) + 0.8 * np.log10(data_3d[4,0]))
     slope_marker((x,y), -2, size_frac = 0.15, invert = True, pad_frac = 0.12, \
@@ -55,9 +74,9 @@ plt.figure()
 plt.loglog(np.reciprocal(data_2d[:,4]), data_2d[:,1], 'bo-', label='$n=2$')
 plt.loglog(np.reciprocal(data_3d[:,4]), data_3d[:,1], 'rs-', label='$n=3$')
 
-if data_3d[0,1] > data_3d[-1,1]:
+if data_3d[0,1] > data_3d[-1,1] and problemType not in [1,7]:
     x = 1.0 / data_3d[3,4]
-    y = 10 ** (0.1 * np.log10(data_3d[3,1]) + 0.9 * np.log10(data_3d[4,1]))
+    y = 10 ** (0.05 * np.log10(data_3d[3,1]) + 0.95 * np.log10(data_3d[4,1]))
     slope_marker((x,y), -2, size_frac = 0.15, invert = True, pad_frac = 0.12, \
         poly_kwargs={'ec': 'black', 'fill': False}, \
         text_kwargs={'size': 'x-large', 'text': '2', 'usetex': True})