diff --git a/dune/phasefield/utility/ISTLBackend_SEQ_Solvers.hh b/dune/phasefield/utility/ISTLBackend_SEQ_Solvers.hh
index af1324b37d6ba965959ae3a095ce151c0126fa7e..509fb9cab1f1f3c339370d3b2e4a88e6e50bb05a 100644
--- a/dune/phasefield/utility/ISTLBackend_SEQ_Solvers.hh
+++ b/dune/phasefield/utility/ISTLBackend_SEQ_Solvers.hh
@@ -2,6 +2,7 @@
 
 #include<dune/pdelab/backend/istl.hh>
 #include "SEQ_Uzawa_preconditioner.hh"
+#include "SEQ_SIMPLE_preconditioner.hh"
 
 template<template<class> class Solver>
 class ISTLBackend_SEQ_Richardson
@@ -228,8 +229,268 @@ private :
   const Dune::ParameterTree& params;
 };
 
+/** \brief Linear solver backend for Restarted GMRes solver preconditioned with the SIMPLE preconditioner
+  */
+class ISTLBackend_SEQ_GMRES_SIMPLE
+{
+public :
+  /*! \brief make a linear solver object
+
+      \param[in] restart_ number of iterations when GMRes has to be restarted
+      \param[in] maxiter_ maximum number of iterations to do
+      \param[in] verbose_ print messages if true
+  */
+  explicit ISTLBackend_SEQ_GMRES_SIMPLE(int restart_ = 200, int maxiter_ = 5000, int verbose_ = 1, const Dune::ParameterTree& params_ = {})
+    : restart(restart_), maxiter(maxiter_), verbose(verbose_), params(params_)
+  {}
+  
+  /*! \brief compute global norm of a vector
+
+      \param[in] v the given vector
+  */
+  template<class V>
+  typename Dune::template FieldTraits<typename V::ElementType >::real_type norm(const V& v) const
+  {
+    return v.two_norm();
+  }
+
+  /** \brief solve the given linear system
+
+      \param[in] A the given matrix
+      \param[out] z the solution vector to be computed
+      \param[in] r right hand side
+      \param[in] reduction to be achieved
+  */
+  template<class M, class V, class W>
+  void apply(M& A, V& z, W& r, typename Dune::template FieldTraits<typename W::ElementType>::real_type reduction)
+  {
+    using Dune::PDELab::Backend::Native;
+    using Dune::PDELab::Backend::native;
+    
+    Dune::MatrixAdapter<Native<M>,
+                        Native<V>,
+                        Native<W>> opa(native(A));
+                        
+    SeqSimple<Native<M>,Native<V>,Native<W>> prec(native(A), params);
+    Dune::RestartedGMResSolver<Native<V>> solver(opa, prec, reduction, restart, maxiter, verbose);
+    
+    Dune::InverseOperatorResult stat;
+    solver.apply(native(z), native(r), stat);
+    res.converged  = stat.converged;
+    res.iterations = stat.iterations;
+    res.elapsed    = stat.elapsed;
+    res.reduction  = stat.reduction;
+    res.conv_rate  = stat.conv_rate;
+  }
+  
+  const Dune::PDELab::LinearSolverResult<double>& result() const
+  {
+    return res;
+  }  
+
+private :
+  int restart, maxiter, verbose;
+  Dune::PDELab::LinearSolverResult<double> res;
+  const Dune::ParameterTree& params;
+};
+
+/** \brief Linear solver backend for Restarted Flexible GMRes preconditioned with ILU(0)
+  */
+class ISTLBackend_SEQ_FGMRES_ILU0
+{
+public :
+  /** \brief make linear solver object
+      
+      \param[in] restart_ number of iterations when GMRes has to be restarted
+      \param[in] maxiter_ maximum number of iterations to do
+      \param[in] verbose_ print messages if true
+  */
+  explicit ISTLBackend_SEQ_FGMRES_ILU0(int restart_ = 200, int maxiter_ = 5000, int verbose_ = 1)
+    : restart(restart_), maxiter(maxiter_), verbose(verbose_)
+  {}
+  
+  /*! \brief compute global norm of a vector
+
+      \param[in] v the given vector
+  */
+  template<class V>
+  typename Dune::template FieldTraits<typename V::ElementType >::real_type norm(const V& v) const
+  {
+    return v.two_norm();
+  }
+
+  /** \brief solve the given linear system
+
+      \param[in] A the given matrix
+      \param[out] z the solution vector to be computed
+      \param[in] r right hand side
+      \param[in] reduction to be achieved
+  */
+  template<class M, class V, class W>
+  void apply(M& A, V& z, W& r, typename Dune::template FieldTraits<typename W::ElementType>::real_type reduction)
+  {
+    using Dune::PDELab::Backend::Native;
+    using Dune::PDELab::Backend::native;
+    
+    Dune::MatrixAdapter<Native<M>,
+                        Native<V>,
+                        Native<W>> opa(native(A));
+                        
+    Dune::SeqILU<Native<M>,
+                 Native<V>,
+                 Native<W>> ilu0(native(A), 1.0);
+                 
+    Dune::RestartedFlexibleGMResSolver<Native<V>> solver(opa,ilu0,reduction,restart,maxiter,verbose);
+    Dune::InverseOperatorResult stat;
+    solver.apply(native(z), native(r), stat);
+    res.converged  = stat.converged;
+    res.iterations = stat.iterations;
+    res.elapsed    = stat.elapsed;
+    res.reduction  = stat.reduction;
+    res.conv_rate  = stat.conv_rate;
+  }
+  
+  const Dune::PDELab::LinearSolverResult<double>& result() const
+  {
+    return res;
+  }  
+
+
+private :
+  int restart, maxiter, verbose;
+  Dune::PDELab::LinearSolverResult<double> res;
+};
+
+/** \brief Linear solver backend for Restarted Flexible GMRes solver preconditioned with the Uzawa preconditioner
+  */
+class ISTLBackend_SEQ_FGMRES_Uzawa
+{
+public :
+  /*! \brief make a linear solver object
+
+      \param[in] restart_ number of iterations when GMRes has to be restarted
+      \param[in] maxiter_ maximum number of iterations to do
+      \param[in] verbose_ print messages if true
+  */
+  explicit ISTLBackend_SEQ_FGMRES_Uzawa(int restart_ = 200, int maxiter_ = 5000, int verbose_ = 1, const Dune::ParameterTree& params_ = {})
+    : restart(restart_), maxiter(maxiter_), verbose(verbose_), params(params_)
+  {}
+  
+  /*! \brief compute global norm of a vector
+
+      \param[in] v the given vector
+  */
+  template<class V>
+  typename Dune::template FieldTraits<typename V::ElementType >::real_type norm(const V& v) const
+  {
+    return v.two_norm();
+  }
+
+  /** \brief solve the given linear system
+
+      \param[in] A the given matrix
+      \param[out] z the solution vector to be computed
+      \param[in] r right hand side
+      \param[in] reduction to be achieved
+  */
+  template<class M, class V, class W>
+  void apply(M& A, V& z, W& r, typename Dune::template FieldTraits<typename W::ElementType>::real_type reduction)
+  {
+    using Dune::PDELab::Backend::Native;
+    using Dune::PDELab::Backend::native;
+    
+    Dune::MatrixAdapter<Native<M>,
+                        Native<V>,
+                        Native<W>> opa(native(A));
+                        
+    SeqUzawa<Native<M>,Native<V>,Native<W>> prec(native(A), params);
+    Dune::RestartedFlexibleGMResSolver<Native<V>> solver(opa, prec, reduction, restart, maxiter, verbose);
+    
+    Dune::InverseOperatorResult stat;
+    solver.apply(native(z), native(r), stat);
+    res.converged  = stat.converged;
+    res.iterations = stat.iterations;
+    res.elapsed    = stat.elapsed;
+    res.reduction  = stat.reduction;
+    res.conv_rate  = stat.conv_rate;
+  }
+  
+  const Dune::PDELab::LinearSolverResult<double>& result() const
+  {
+    return res;
+  }  
+
+private :
+  int restart, maxiter, verbose;
+  Dune::PDELab::LinearSolverResult<double> res;
+  const Dune::ParameterTree& params;
+};
+
+/** \brief Linear solver backend for Restarted Flexible GMRes solver preconditioned with the SIMPLE preconditioner
+  */
+class ISTLBackend_SEQ_FGMRES_SIMPLE
+{
+public :
+  /*! \brief make a linear solver object
+
+      \param[in] restart_ number of iterations when GMRes has to be restarted
+      \param[in] maxiter_ maximum number of iterations to do
+      \param[in] verbose_ print messages if true
+  */
+  explicit ISTLBackend_SEQ_FGMRES_SIMPLE(int restart_ = 200, int maxiter_ = 5000, int verbose_ = 1, const Dune::ParameterTree& params_ = {})
+    : restart(restart_), maxiter(maxiter_), verbose(verbose_), params(params_)
+  {}
+  
+  /*! \brief compute global norm of a vector
+
+      \param[in] v the given vector
+  */
+  template<class V>
+  typename Dune::template FieldTraits<typename V::ElementType >::real_type norm(const V& v) const
+  {
+    return v.two_norm();
+  }
+
+  /** \brief solve the given linear system
+
+      \param[in] A the given matrix
+      \param[out] z the solution vector to be computed
+      \param[in] r right hand side
+      \param[in] reduction to be achieved
+  */
+  template<class M, class V, class W>
+  void apply(M& A, V& z, W& r, typename Dune::template FieldTraits<typename W::ElementType>::real_type reduction)
+  {
+    using Dune::PDELab::Backend::Native;
+    using Dune::PDELab::Backend::native;
+    
+    Dune::MatrixAdapter<Native<M>,
+                        Native<V>,
+                        Native<W>> opa(native(A));
+                        
+    SeqSimple<Native<M>,Native<V>,Native<W>> prec(native(A), params);
+    Dune::RestartedFlexibleGMResSolver<Native<V>> solver(opa, prec, reduction, restart, maxiter, verbose);
+    
+    Dune::InverseOperatorResult stat;
+    solver.apply(native(z), native(r), stat);
+    res.converged  = stat.converged;
+    res.iterations = stat.iterations;
+    res.elapsed    = stat.elapsed;
+    res.reduction  = stat.reduction;
+    res.conv_rate  = stat.conv_rate;
+  }
+  
+  const Dune::PDELab::LinearSolverResult<double>& result() const
+  {
+    return res;
+  }  
+
+private :
+  int restart, maxiter, verbose;
+  Dune::PDELab::LinearSolverResult<double> res;
+  const Dune::ParameterTree& params;
+};
 
-// create Uzawa-, SIMPLE(R)-type preconditioners (istl)
 
 // create CH block preconditioner
 
diff --git a/dune/phasefield/utility/SEQ_SIMPLE_preconditioner.hh b/dune/phasefield/utility/SEQ_SIMPLE_preconditioner.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a1a7c2f502c8ff018f1aedcb8026d7abf97d886e
--- /dev/null
+++ b/dune/phasefield/utility/SEQ_SIMPLE_preconditioner.hh
@@ -0,0 +1,668 @@
+#include <dune/common/exceptions.hh>
+#include <dune/common/float_cmp.hh>
+#include <dune/common/indices.hh>
+#include <dune/common/version.hh>
+#include <dune/istl/preconditioners.hh>
+#include <dune/istl/paamg/amg.hh>
+#include <dune/istl/matrixindexset.hh>
+
+#if HAVE_UMFPACK
+#include <dune/istl/umfpack.hh>
+#endif
+
+/*!
+ * \brief A preconditioner based on the SIMPLE algorithm for saddle-point problems of the form
+ * \f$
+ \begin{pmatrix}
+    A & B \\
+    C & D
+ \end{pmatrix}
+
+ \begin{pmatrix}
+    u\\
+    p
+ \end{pmatrix}
+
+ =
+
+ \begin{pmatrix}
+    f\\
+    g
+ \end{pmatrix}
+ * \f$
+ *
+ * See: https://www.cs.umd.edu/~elman/papers/tax.pdf
+ *
+ * \tparam M Type of the matrix.
+ * \tparam X Type of the update.
+ * \tparam Y Type of the defect.
+ * \tparam l Preconditioner block level (for compatibility reasons, unused).
+ */
+template<class M, class X, class Y, int l = 1>
+class SeqSimple : public Dune::Preconditioner<X,Y>
+{
+  typedef std::decay_t<decltype(std::declval<M>()[Dune::Indices::_0][Dune::Indices::_0])> A;
+  typedef std::decay_t<decltype(std::declval<X>()[Dune::Indices::_0])> U;
+  typedef std::decay_t<decltype(std::declval<M>()[Dune::Indices::_1][Dune::Indices::_1])> D;
+  typedef std::decay_t<decltype(std::declval<X>()[Dune::Indices::_1])> P;
+  
+  typedef Dune::Amg::SequentialInformation Comm;
+  typedef Dune::MatrixAdapter<A, U, U> LinearOperator;
+  typedef Dune::SeqSSOR<A, U, U> Smoother;
+  typedef Dune::Amg::AMG<LinearOperator, U, Smoother, Comm> AMGForA;
+
+  typedef Dune::Amg::SequentialInformation CommSchur;
+  typedef Dune::MatrixAdapter<D, P, P> LinearOperatorSchur;
+  typedef Dune::SeqSSOR<D, P, P> SmootherSchur;
+  typedef Dune::Amg::AMG<LinearOperatorSchur, P, SmootherSchur, CommSchur> AMGForSchur;
+  
+  class SimpleOperator : public Dune::LinearOperator<P, P>
+  {
+  public:
+    SimpleOperator(const M& m) : m_(m) {}
+
+    template<class S>
+    void setSolver(const S& solver)
+    { solver_ = solver; }
+
+    /*! \brief apply operator to x:  \f$ y = A(x) \f$
+        The input vector is consistent and the output must also be
+        consistent on the interior+border partition.
+     */
+    void apply (const P& x, P& y) const final
+    {
+      // convenience variables
+      const auto& deltaP = x;
+      auto& rhs = y;
+
+      using namespace Dune::Indices;
+      auto& B = m_[_0][_1];
+      auto& C = m_[_1][_0];
+      auto& D = m_[_1][_1];
+
+      // Apply the (approximate) Schur complement S * deltaP = (D - C * Q_A^-1 * B) * deltaP:
+
+      // B * deltaP
+      // rhsTmp has different size than rhs
+      auto rhsTmp = U(B.N());
+      B.mv(deltaP, rhsTmp);
+
+      // Q_A^-1 * B * deltaP
+      auto rhsTmp2 = rhsTmp;
+      Dune::InverseOperatorResult result;
+      solver_(rhsTmp, rhsTmp2, result);
+
+      // C * Q_A^-1 * B * deltaP
+      C.mv(rhsTmp, rhs);
+
+      // - C * Q_A^-1 * B * deltaP
+      rhs *= -1.0;
+
+      // (D - C * Q_A^-1 * B) * deltaP
+      D.umv(deltaP, rhs);
+    }
+
+    //! apply operator to x, scale and add:  \f$ y = y + \alpha A(x) \f$
+    void applyscaleadd (typename P::field_type alpha, const P& x, P& y) const final
+    {
+      auto tmp = P(y.size());
+      apply(x, tmp);
+      y.axpy(alpha, tmp);
+    }
+
+    //! Category of the linear operator (see SolverCategory::Category)
+    Dune::SolverCategory::Category category() const final
+    {
+      return Dune::SolverCategory::sequential;
+    };
+
+    private:
+      //! The system matrix
+      const M& m_;
+
+      //! Applies the effect of Q_A^-1 [A^-1 or diag(A)^-1 (depending on what is chosen in setSolver)]
+      std::function<void(U&, U&, Dune::InverseOperatorResult&)> solver_;
+  };
+  
+public:
+  //! \brief The matrix type the preconditioner is for.
+  typedef M matrix_type;
+  //! \brief The domain type of the preconditioner.
+  typedef X domain_type;
+  //! \brief The range type of the preconditioner.
+  typedef Y range_type;
+  //! \brief The field type of the preconditioner.
+  typedef typename X::field_type field_type;
+  //! \brief scalar type underlying the field_type
+  typedef Dune::Simd::Scalar<field_type> scalar_field_type;
+  //! \brief real scalar type underlying the field_type
+  typedef typename Dune::FieldTraits<scalar_field_type>::real_type real_field_type;
+  
+
+  /*!
+   * \brief Constructor
+   *
+   * \param mat The matrix to operate on.
+   * \param params Collection of paramters.
+   */
+  SeqSimple(const M& mat, const Dune::ParameterTree& params)
+    : matrix_(mat)
+    , params_(params)
+    , numIterations_(params.get<std::size_t>("NumIterations", 1))
+    , relaxationFactorP_(params.get<scalar_field_type>("Relaxation", 1.0))
+    , relaxationFactorU_(relaxationFactorP_)
+    , verbosity_(params.get<int>("VerbosityLevel", 1))
+    , useStandardSolverForA_(params.get<bool>("UseStandardSolverForA", false))
+    , useDirectSolverForA_(params.get<bool>("UseDirectSolverForA", false))
+    , useDiagonalInSchurComplement_(params.get<bool>("UseDiagonalInSchurComplement", false))
+    , useDiagonalInUpdate_(params.get<bool>("UseDiagonalInUpdate", false))
+    , useStandardSolverForSchurComplement_(params.get<bool>("UseStandardSolverForSchurComplement", false))
+    , useDirectSolverForSchurComplement_(params.get<bool>("UseDirectSolverForSchurComplement", false))
+    , useStandardSolverForAInSchurComplement_(params.get<bool>("UseStandardSolverForAInSchurComplement", false))
+  {
+    if(useStandardSolverForA_){
+      initAMGPreconditionerForA_(params);
+      initStandardSolverForA_();
+      if(!useStandardSolverForAInSchurComplement_){
+        if(!useDirectSolverForA_)
+          initAMGSolverForA_(params);
+        else
+          initUMFPackForA_();
+      }
+    }
+    else if(!useDirectSolverForA_)
+      initAMGSolverForA_(params);
+    else
+      initUMFPackForA_();
+
+    relaxationFactorP_ = params.get<scalar_field_type>("RelaxationP", relaxationFactorP_);
+    relaxationFactorU_ = params.get<scalar_field_type>("RelaxationU", relaxationFactorU_);
+
+    if(useStandardSolverForSchurComplement_){
+      initAMGPreconditionerForSchur_(params);
+      initStandardSchurComplementSolver_();
+    }
+    else if(!useDirectSolverForSchurComplement_)
+      initAMGSolverForSchur_(params);
+    else
+      initUMFPackForSchur_();
+  }
+
+  /*!
+   * \brief Prepare the preconditioner.
+   */
+  virtual void pre(X& x, Y& b) {}
+  
+  /*!
+   * \brief Apply the preconditioner
+   *
+   * \param update The update to be computed.
+   * \param currentDefect The current defect.
+   */
+  virtual void apply(X& update, const Y& currentDefect)
+  {
+    using namespace Dune::Indices;
+
+    auto& A = matrix_[_0][_0];
+    auto& B = matrix_[_0][_1];
+    auto& C = matrix_[_1][_0];
+    auto& D = matrix_[_1][_1];
+
+    const auto& f = currentDefect[_0];
+    const auto& g = currentDefect[_1];
+    auto& u = update[_0];
+    auto& p = update[_1];
+
+    static const bool dirichletHack = params_.get<bool>("DirichletHack", false);
+    // incorporate Dirichlet cell values
+    // TODO: pass Dirichlet constraint handler from outside
+    if (dirichletHack)
+    for (std::size_t i = 0; i < D.N(); ++i)
+    {
+      const auto& block = D[i][i];
+      for (auto rowIt = block.begin(); rowIt != block.end(); ++rowIt)
+        if (Dune::FloatCmp::eq<scalar_field_type>(rowIt->one_norm(), 1.0))
+          p[i][rowIt.index()] = g[i][rowIt.index()];
+    }
+
+    static const std::string SIMPLEType = params_.get<std::string>("SIMPLEType", "SIMPLE");
+    if (SIMPLEType == "SIMPLE") {
+      // the SIMPLE algorithm
+      for (std::size_t k = 0; k < numIterations_; ++k)
+      {
+        // 1. Solve A*uNew + B*p = f for uNew
+        auto uRhs = f;
+        B.mmv(p, uRhs);
+        auto uNew = u;
+        if(useStandardSolverForA_){
+          Dune::InverseOperatorResult result;
+          solverForA_->apply(uNew, uRhs, result);
+        }
+        else
+          applySolverForA_(uNew, uRhs);
+
+        // 2. Solve S * deltaP = g - (C * uNew + D*p) for deltaP
+        auto pRhs = g;
+        C.mmv(uNew, pRhs);
+        D.mmv(p, pRhs);
+        auto deltaP = p;
+        if(useStandardSolverForSchurComplement_){
+          Dune::InverseOperatorResult result1;
+          schurComplementSolver_->apply(deltaP, pRhs, result1);
+        }
+        else
+          applySolverForSchurComplement_(deltaP, pRhs);
+
+        // 3. Calculate correction of u:
+        // deltaU = (-Q_A^-1 * B) * deltaP
+        auto deltaU = U(B.N());
+        B.mv(deltaP, deltaU);
+        if(useDiagonalInUpdate_)
+          applyInverseOfDiagonalOfA_(deltaU);
+        else if(useStandardSolverForA_){
+          auto deltaU2 = deltaU;
+          Dune::InverseOperatorResult result2;
+          solverForA_->apply(deltaU, deltaU2, result2);
+        }
+        else
+          applySolverForA_(deltaU, deltaU);
+
+        deltaU *= -1.0;
+
+        // 4. Update p
+        deltaP *= relaxationFactorP_;
+        p += deltaP;
+        
+        // 5. Update u
+        deltaU += uNew;
+        deltaU *= relaxationFactorU_;
+        u *= (1 - relaxationFactorU_);
+        u += deltaU;
+      }
+    }
+    else if (SIMPLEType == "SIMPLER") {
+      // the SIMPLER algorithm
+      for (std::size_t k = 0; k < numIterations_; ++k)
+      {
+        // 1. Solve S * pNew = g - C*u - C * diag(A)^-1 * (f - A*u)
+        auto uRhs = f;
+        A.mmv(u, uRhs);
+
+        applyInverseOfDiagonalOfA_(uRhs);
+
+        auto pRhs = p;
+        C.mv(uRhs, pRhs);
+
+        C.umv(u, pRhs);
+        pRhs *= -1.0;
+        pRhs += g;
+
+        auto pNew = p;
+        if(useStandardSolverForSchurComplement_){
+          Dune::InverseOperatorResult result;
+          schurComplementSolver_->apply(pNew, pRhs, result);
+        }
+        else
+          applySolverForSchurComplement_(pNew, pRhs);
+
+        // 2. Update p
+        pNew *= relaxationFactorP_;
+        p *= (1 - relaxationFactorP_);
+        p += pNew;
+
+        // 3. Solve A*uNew + B*p = f for uNew
+        auto uRhs2 = f;
+        B.mmv(p, uRhs2);
+        auto uNew = u;
+        if(useStandardSolverForA_){
+          Dune::InverseOperatorResult result1;
+          solverForA_->apply(uNew, uRhs2, result1);
+        }
+        else
+          applySolverForA_(uNew, uRhs2);
+
+        // 4. Solve (D - C * diag(A)^-1 * B) * deltaP = g - (C * uNew + D*p) for deltaP
+        auto pRhs2 = g;
+        C.mmv(uNew, pRhs2);
+        D.mmv(p, pRhs2);
+        auto deltaP = p;
+        if(useStandardSolverForSchurComplement_){
+          Dune::InverseOperatorResult result2;
+          schurComplementSolver_->apply(deltaP, pRhs2, result2);
+        }
+        else
+          applySolverForSchurComplement_(deltaP, pRhs2);
+
+        // 5. Calculate correction of u:
+        // deltaU = (-diag(A^-1) * B) * deltaP
+        auto deltaU = U(B.N());
+        B.mv(deltaP, deltaU);
+
+        applyInverseOfDiagonalOfA_(deltaU);
+
+        deltaU *= -1.0;
+
+        // 6. Update u
+        deltaU += uNew;
+        deltaU *= relaxationFactorU_;
+        u *= (1 - relaxationFactorU_);
+        u += deltaU;
+      }
+    }
+    else
+      DUNE_THROW(Dune::InvalidStateException, SIMPLEType << "not supported. Use SIMPLE, SIMPLER");
+    }
+
+  /*!
+   * \brief Clean up.
+   */
+  virtual void post(X& x) {}
+  
+  //! Category of the preconditioner (see SolverCategory::Category)
+  virtual Dune::SolverCategory::Category category() const
+  {
+    return Dune::SolverCategory::sequential;
+  }
+  
+private:
+  // void apply
+  void applyStandardSIMPLE_()
+  {}
+  
+  void initAMGSolverForA_(const Dune::ParameterTree& params)
+  {
+    using namespace Dune::Indices;
+    auto linearOperator = std::make_shared<LinearOperator>(matrix_[_0][_0]);
+    amgSolverForA_ = std::make_unique<AMGForA>(linearOperator, params);
+  }
+  
+  void initUMFPackForA_()
+  {
+#if HAVE_UMFPACK
+    using namespace Dune::Indices;
+    umfPackSolverForA_ = std::make_unique<Dune::UMFPack<A>>(matrix_[_0][_0]);
+#else
+    DUNE_THROW(Dune::InvalidStateException, "UMFPack not available. Use UseDirectSolverForA = false.");
+#endif
+  }
+  
+  template<class Sol, class Rhs>
+  void applySolverForA_(Sol& sol, Rhs& rhs) const
+  {
+    if (useDirectSolverForA_)
+    {
+#if HAVE_UMFPACK
+      Dune::InverseOperatorResult res;
+      auto rhsTmp = rhs;
+      umfPackSolverForA_->apply(sol, rhsTmp, res);
+#endif
+    }
+    else
+    {
+      amgSolverForA_->pre(sol, rhs);
+      amgSolverForA_->apply(sol, rhs);
+      amgSolverForA_->post(sol);
+    }
+  }
+  
+  void initAMGPreconditionerForA_(const Dune::ParameterTree& params)
+  {
+    using namespace Dune::Indices;
+    auto linearOperator = std::make_shared<LinearOperator>(matrix_[_0][_0]);
+    amgPreconditionerForA_ = std::make_shared<AMGForA>(linearOperator, params);
+  }
+  
+  void initStandardSolverForA_()
+  {
+    using namespace Dune::Indices;
+    auto linearOperator = std::make_shared<LinearOperator>(matrix_[_0][_0]);
+
+    Dune::ParameterTree treeSolverForA;
+    treeSolverForA["verbose"] = params_.get<std::string>("SolverForAVerbosity", "0");
+    treeSolverForA["reduction"] = params_.get<std::string>("SolverForAResidualReduction", "1e-12");
+    treeSolverForA["maxit"] = params_.get<std::string>("SolverForAMaxIter", "1000");
+    treeSolverForA["restart"] = params_.get<std::string>("SolverForARestart", "100");
+
+    static const bool usePreconditionerForA = params_.get<bool>("UsePreconditionerForA", false);
+    if (usePreconditionerForA)
+    {
+      Dune::ParameterTree treePreconditionerA;
+      treePreconditionerA["verbose"] = params_.get<std::string>("SolverForAVerbosity", "0");
+      // preconditionerForA_ = std::make_shared<SeqJacobiMatrixFree<U, U>>(linearOperator, treePreconditionerA);
+      preconditionerForA_ = amgPreconditionerForA_; // std::make_shared<Dune::SeqJac<A, U, U>>(matrix_[_0][_0], 1, 1.0);
+    }
+    else
+      preconditionerForA_ = std::make_shared<Dune::Richardson<U, U>>();
+
+    static const auto solverForAType = params_.get<std::string>("SolverForAType", "restartedgmressolver");
+
+    if (solverForAType == "restartedgmressolver")
+      solverForA_ = std::make_unique<Dune::RestartedGMResSolver<U>>(linearOperator, preconditionerForA_, treeSolverForA);
+    else if (solverForAType == "bicgstabsolver")
+      solverForA_ = std::make_unique<Dune::BiCGSTABSolver<U>>(linearOperator, preconditionerForA_, treeSolverForA);
+    else if (solverForAType == "cgsolver")
+      solverForA_ = std::make_unique<Dune::CGSolver<U>>(linearOperator, preconditionerForA_, treeSolverForA);
+    else
+      DUNE_THROW(Dune::InvalidStateException, solverForAType << "not supported. Use restartedgmressolver, bicgstabsolver or cgsolver");
+  }
+  
+  void initAMGSolverForSchur_(const Dune::ParameterTree& params)
+  {
+    schurMatrix_ = schurApproximate_();
+    auto linearOperatorSchur = std::make_shared<LinearOperatorSchur>(*schurMatrix_);
+    amgSolverForSchur_ = std::make_unique<AMGForSchur>(linearOperatorSchur, params);
+  }
+
+  void initUMFPackForSchur_()
+  {
+#if HAVE_UMFPACK
+    schurMatrix_ = schurApproximate_();
+    umfPackSolverForSchur_ = std::make_unique<Dune::UMFPack<D>>(*schurMatrix_);
+#else
+    DUNE_THROW(Dune::InvalidStateException, "UMFPack not available. Use UseDirectSolverForSchurComplement = false.");
+#endif
+  }
+
+  template<class Sol, class Rhs>
+  void applySolverForSchurComplement_(Sol& sol, Rhs& rhs) const
+  {
+    if (useDirectSolverForSchurComplement_)
+    {
+#if HAVE_UMFPACK
+      Dune::InverseOperatorResult res;
+      auto rhsTmp = rhs;
+      umfPackSolverForSchur_->apply(sol, rhsTmp, res);
+#endif
+    }
+    else
+    {
+      amgSolverForSchur_->pre(sol, rhs);
+      amgSolverForSchur_->apply(sol, rhs);
+      amgSolverForSchur_->post(sol);
+    }
+  }
+
+  void initAMGPreconditionerForSchur_(const Dune::ParameterTree& params)
+  {
+    schurMatrix_ = schurApproximate_();
+    auto linearOperatorSchur = std::make_shared<LinearOperatorSchur>(*schurMatrix_);
+    amgPreconditionerForSchur_ = std::make_shared<AMGForSchur>(linearOperatorSchur, params);
+  }
+  
+  // explicit assembly of the approximate Schur complement matrix [D - C * diag(A)^-1 * B]
+  auto schurApproximate_()
+  {
+    using namespace Dune::Indices;
+    auto& A = matrix_[_0][_0];
+    auto& B = matrix_[_0][_1];
+    auto& C = matrix_[_1][_0];
+    auto& D = matrix_[_1][_1];
+
+    using AType = std::decay_t<decltype(A)>;
+    using BType = std::decay_t<decltype(B)>;
+    using DType = std::decay_t<decltype(D)>;
+
+    const std::size_t sizeA = A.N();
+
+    //get the diagonal matrix invDiagA = diag(A)^-1
+    AType invDiagA;
+    invDiagA.setBuildMode(AType::random);
+    setDiagPattern(invDiagA, sizeA);
+
+    auto row = A.begin();
+
+    for(; row != A.end(); ++row)
+    {
+      using size_type = typename AType::size_type;
+      size_type rowIdx = row.index();
+      invDiagA[rowIdx][rowIdx] = 1./(A[rowIdx][rowIdx]);
+    }
+
+    // diag(A)^-1 * B
+    BType invAB;
+    Dune::matMultMat(invAB, invDiagA, B);
+
+    // C * diag(A)^-1 * B
+    DType schurApproximate;
+    Dune::matMultMat(schurApproximate, C, invAB);
+
+    // D - C * diag(A)^-1 * B
+    schurApproximate *= -1.0;
+    schurApproximate += D;
+
+    // const std::size_t sizeS = schurApproximate.N();
+    //
+    // //get the diagonal matrix invDiagS = diag(S)^-1
+    // DType invDiagS;
+    // invDiagS.setBuildMode(DType::random);
+    // setDiagPattern(invDiagS, sizeS);
+    //
+    // auto rowS = schurApproximate.begin();
+    //
+    // for(; rowS != schurApproximate.end(); ++rowS)
+    // {
+    //     using size_type = typename DType::size_type;
+    //     size_type rowSIdx = rowS.index();
+    //     invDiagS[rowSIdx][rowSIdx] = 1./(schurApproximate[rowSIdx][rowSIdx]);
+    // }
+
+    // return std::make_unique<DType>(invDiagS);
+
+    return std::make_unique<DType>(schurApproximate);
+  }
+  
+  template <class MType>
+  void setDiagPattern(MType& diagM, std::size_t size)
+  {
+    // set the size of the sub-matrices
+    diagM.setSize(size, size);
+
+    // set occupation pattern of the coefficient matrix
+    Dune::MatrixIndexSet occupationPatternDiagM;
+    occupationPatternDiagM.resize(size, size);
+
+    // evaluate the acutal pattern
+    for (int i = 0; i < diagM.N(); ++i)
+    {
+      occupationPatternDiagM.add(i, i);
+    }
+
+    occupationPatternDiagM.exportIdx(diagM);
+  }
+  
+  void initStandardSchurComplementSolver_()
+  {
+    auto linearOperator = std::make_shared<SimpleOperator>(matrix_);
+    if(useDiagonalInSchurComplement_)
+      linearOperator->setSolver([&](U& a, U& b, Dune::InverseOperatorResult result) { applyInverseOfDiagonalOfA_(a); });
+    else if(useStandardSolverForA_ && useStandardSolverForAInSchurComplement_){
+      linearOperator->setSolver([&](U& a, U& b, Dune::InverseOperatorResult result) { solverForA_->apply(a, b, result); });
+    }
+    else
+      linearOperator->setSolver([&](U& a, U& b, Dune::InverseOperatorResult result) { applySolverForA_(a, b); });
+
+    Dune::ParameterTree treeSchurComplementSolver;
+    treeSchurComplementSolver["verbose"] = params_.get<std::string>("SolverForSchurVerbosity", "0");
+    treeSchurComplementSolver["reduction"] = params_.get<std::string>("SolverForSchurResidualReduction", "1e-12");
+    treeSchurComplementSolver["maxit"] = params_.get<std::string>("SolverForSchurMaxIter", "1000");
+    treeSchurComplementSolver["restart"] = params_.get<std::string>("SolverForSchurRestart", "100");
+
+    static const bool usePreconditionerForSchurComplement = params_.get<bool>("UsePreconditionerForSchurComplement", false);
+    if (usePreconditionerForSchurComplement)
+    {
+      Dune::ParameterTree treePreconditionerSchur;
+      treePreconditionerSchur["verbose"] = params_.get<std::string>("SolverForSchurVerbosity", "0");
+      // schurComplementPreconditioner_ = std::make_shared<SeqJacobiMatrixFree<P, P>>(linearOperator, treePreconditionerSchur);
+      schurComplementPreconditioner_ = amgPreconditionerForSchur_; // std::make_shared<Dune::SeqJac<D, P, P>>(*schurMatrix_, 1, 1.0);
+    }
+    else
+      schurComplementPreconditioner_ = std::make_shared<Dune::Richardson<P, P>>();
+
+    static const auto schurComplementSolverType = params_.get<std::string>("SolverForSchurType", "restartedgmressolver");
+
+    if (schurComplementSolverType == "restartedgmressolver")
+      schurComplementSolver_ = std::make_unique<Dune::RestartedGMResSolver<P>>(linearOperator, schurComplementPreconditioner_, treeSchurComplementSolver);
+    else if (schurComplementSolverType == "bicgstabsolver")
+      schurComplementSolver_ = std::make_unique<Dune::BiCGSTABSolver<P>>(linearOperator, schurComplementPreconditioner_, treeSchurComplementSolver);
+    else if (schurComplementSolverType == "cgsolver")
+      schurComplementSolver_ = std::make_unique<Dune::CGSolver<P>>(linearOperator, schurComplementPreconditioner_, treeSchurComplementSolver);
+    else
+      DUNE_THROW(Dune::InvalidStateException, schurComplementSolverType << "not supported. Use restartedgmressolver, bicgstabsolver or cgsolver");
+  }
+  
+  void applyInverseOfDiagonalOfA_(U& x) const
+  {
+    using namespace Dune::Indices;
+    const auto& A = matrix_[_0][_0];
+
+    for (std::size_t i = 0; i < A.N(); ++i)
+    {
+      auto tmp = A[i][i];
+      tmp.invert();
+      x[i] *= tmp;
+    }
+  }
+
+  //! \brief The matrix we operate on.
+  const M& matrix_;
+  //! \brief The number of steps to do in apply
+  const std::size_t numIterations_;
+  //! \brief The relaxation factor to use
+  scalar_field_type relaxationFactorP_;
+  scalar_field_type relaxationFactorU_;
+  //! \brief The verbosity level
+  const int verbosity_;
+
+  std::unique_ptr<AMGForA> amgSolverForA_;
+  std::shared_ptr<AMGForA> amgPreconditionerForA_;
+  std::unique_ptr<Dune::IterativeSolver<U,U>> solverForA_;
+  std::shared_ptr<Dune::Preconditioner<U,U>> preconditionerForA_;
+  std::unique_ptr<AMGForSchur> amgSolverForSchur_;
+  std::shared_ptr<AMGForSchur> amgPreconditionerForSchur_;
+  std::unique_ptr<Dune::IterativeSolver<P,P>> schurComplementSolver_;
+  std::shared_ptr<Dune::Preconditioner<P,P>> schurComplementPreconditioner_;
+  std::unique_ptr<A> A_;
+  std::unique_ptr<D> schurMatrix_;
+#if HAVE_UMFPACK
+  std::unique_ptr<Dune::UMFPack<A>> umfPackSolverForA_;
+  std::unique_ptr<Dune::UMFPack<D>> umfPackSolverForSchur_;
+#endif
+  const std::string paramGroup_;
+  const bool useStandardSolverForA_;
+  const bool useDirectSolverForA_;
+  const bool useDiagonalInSchurComplement_;
+  const bool useDiagonalInUpdate_;
+  const bool useStandardSolverForSchurComplement_;
+  const bool useDirectSolverForSchurComplement_;
+  const bool useStandardSolverForAInSchurComplement_;
+  
+  const Dune::ParameterTree& params_;
+};
+// DUNE_REGISTER_PRECONDITIONER("simple", defaultPreconditionerBlockLevelCreator<SeqSimple>());
+
+
+
+
+
+
+
diff --git a/dune/phasefield/utility/SEQ_Uzawa_preconditioner.hh b/dune/phasefield/utility/SEQ_Uzawa_preconditioner.hh
index 78a22d0c60f1e2e24cef2a597757176e1fec2e03..0e17bdf14fd6e67f9b6684edaf3d77b24c5f83f0 100644
--- a/dune/phasefield/utility/SEQ_Uzawa_preconditioner.hh
+++ b/dune/phasefield/utility/SEQ_Uzawa_preconditioner.hh
@@ -5,6 +5,10 @@
 #include <dune/istl/preconditioners.hh>
 #include <dune/istl/paamg/amg.hh>
 
+#if HAVE_UMFPACK
+#include <dune/istl/umfpack.hh>
+#endif
+
 /*!
  * \brief A preconditioner based on the Uzawa algorithm for saddle-point problems of the form
  * \f$
@@ -69,8 +73,8 @@ public:
    * \param mat The matrix to operate on.
    * \param params Collection of paramters.
    */
-  SeqUzawa(const M& op, const Dune::ParameterTree& params)
-    : matrix_(op)
+  SeqUzawa(const M& mat, const Dune::ParameterTree& params)
+    : matrix_(mat)
     , numIterations_(params.get<std::size_t>("NumIterations", 1))
     , relaxationFactor_(params.get<scalar_field_type>("Relaxation", 1.0))
     , verbosity_(params.get<int>("VerbosityLevel", 1))
@@ -191,9 +195,9 @@ private:
    * This seems to work rather well for various applications.
    * We will underestimate omega by a factor of 2 in the worst case (i.e, lambdaMin = 0).
    *
-   * When facing convergence issues, you may set LinearSolver.Preconditioner.Verbosity = 1 to see the estimate of lambdaMax.
-   * In a new simulation run, you can then set LinearSolver.Preconditioner.DetermineRelaxationFactor = false and set some other value
-   * for LinearSolver.Preconditioner.Relaxation based on the estimate of lambdaMax.
+   * When facing convergence issues, you may set VerbosityLevel = 1 to see the estimate of lambdaMax.
+   * In a new simulation run, you can then set DetermineRelaxationFactor = false and set some other value
+   * for Relaxation based on the estimate of lambdaMax.
    *
    * See: Benzi, M., Golub, G. H., & Liesen, J. (2005). Numerical solution of saddle point problems. Acta numerica, 14, 1-137.
    */