From bd9cc7c0eb25d2f3c527cb15c882cbc53d186a2d Mon Sep 17 00:00:00 2001
From: "Praetorius, Simon" <simon.praetorius@tu-dresden.de>
Date: Mon, 30 Dec 2019 23:32:03 +0100
Subject: [PATCH] Matrix-Vector facade class

---
 doc/doxygen/Doxylocal                         |   5 +-
 src/amdis/BiLinearForm.hpp                    |  33 +-
 src/amdis/BiLinearForm.inc.hpp                |  16 +-
 src/amdis/DOFVector.hpp                       |  53 +-
 src/amdis/DOFVector.inc.hpp                   |   8 +-
 src/amdis/DataTransfer.inc.hpp                |   4 +-
 src/amdis/LinearAlgebra.hpp                   |   4 +-
 src/amdis/LinearForm.hpp                      |  34 +-
 src/amdis/LinearForm.inc.hpp                  |  16 +-
 src/amdis/Observer.hpp                        |  75 +--
 src/amdis/ProblemStat.inc.hpp                 |   4 +-
 src/amdis/functions/CMakeLists.txt            |   1 +
 src/amdis/functions/Interpolate.hpp           |   7 +-
 src/amdis/functions/NodeIndices.hpp           |   8 +-
 src/amdis/functions/ParallelGlobalBasis.hpp   |   6 +-
 src/amdis/functions/SizeInfo.hpp              |  89 ++++
 src/amdis/gridfunctions/DiscreteFunction.hpp  | 255 +++++-----
 .../gridfunctions/DiscreteFunction.inc.hpp    |  26 +-
 .../DiscreteLocalFunction.inc.hpp             |  32 +-
 src/amdis/io/FileWriterCreator.hpp            |  28 +-
 src/amdis/linearalgebra/CMakeLists.txt        |   6 +-
 src/amdis/linearalgebra/Constraints.hpp       |  12 +-
 src/amdis/linearalgebra/DOFMapping.hpp        |   2 +
 src/amdis/linearalgebra/MatrixBase.hpp        | 133 -----
 src/amdis/linearalgebra/MatrixFacade.hpp      | 107 +++++
 src/amdis/linearalgebra/SparsityPattern.hpp   | 155 ++++++
 src/amdis/linearalgebra/VectorBase.hpp        | 454 +++---------------
 src/amdis/linearalgebra/VectorFacade.hpp      | 370 ++++++++++++++
 src/amdis/linearalgebra/eigen/CMakeLists.txt  |   1 +
 src/amdis/linearalgebra/eigen/Constraints.hpp |  12 +-
 .../linearalgebra/eigen/MatrixBackend.hpp     |  18 +-
 src/amdis/linearalgebra/eigen/MatrixSize.hpp  |  60 +++
 src/amdis/linearalgebra/eigen/Traits.hpp      |  19 +-
 .../linearalgebra/eigen/VectorBackend.hpp     |  85 +---
 src/amdis/linearalgebra/istl/Constraints.hpp  |  10 +-
 .../linearalgebra/istl/MatrixBackend.hpp      |  47 +-
 src/amdis/linearalgebra/istl/Traits.hpp       |  44 +-
 .../linearalgebra/istl/VectorBackend.hpp      |  98 ++--
 src/amdis/linearalgebra/mtl/CMakeLists.txt    |   1 +
 src/amdis/linearalgebra/mtl/Constraints.hpp   |  12 +-
 src/amdis/linearalgebra/mtl/MatrixBackend.hpp |  45 +-
 src/amdis/linearalgebra/mtl/SlotSize.hpp      |  90 ++++
 src/amdis/linearalgebra/mtl/Traits.hpp        |  20 +-
 src/amdis/linearalgebra/mtl/VectorBackend.hpp |  88 +---
 .../linearalgebra/petsc/Communication.hpp     |  10 +-
 src/amdis/linearalgebra/petsc/Constraints.hpp |  12 +-
 .../linearalgebra/petsc/MatrixBackend.hpp     |  64 +--
 .../petsc/MatrixNnzStructure.hpp              |  43 +-
 .../petsc/MatrixNnzStructure.inc.hpp          |  16 +-
 src/amdis/linearalgebra/petsc/Traits.hpp      |  13 +-
 .../linearalgebra/petsc/VectorBackend.hpp     |  87 ++--
 src/amdis/typetree/MultiIndex.hpp             |   9 +
 test/DOFVectorTest.cpp                        |  57 ++-
 test/DiscreteFunctionTest.cpp                 |   4 +-
 test/ExpressionsTest.cpp                      |   2 +-
 test/IntegrateTest.cpp                        |   2 +-
 test/ObserverTest.cpp                         |  12 +-
 test/PETScCommTest.cpp                        |   2 +-
 test/ProblemStatTest.cpp                      |  13 +-
 59 files changed, 1651 insertions(+), 1288 deletions(-)
 create mode 100644 src/amdis/functions/SizeInfo.hpp
 delete mode 100644 src/amdis/linearalgebra/MatrixBase.hpp
 create mode 100644 src/amdis/linearalgebra/MatrixFacade.hpp
 create mode 100644 src/amdis/linearalgebra/SparsityPattern.hpp
 create mode 100644 src/amdis/linearalgebra/VectorFacade.hpp
 create mode 100644 src/amdis/linearalgebra/eigen/MatrixSize.hpp
 create mode 100644 src/amdis/linearalgebra/mtl/SlotSize.hpp

diff --git a/doc/doxygen/Doxylocal b/doc/doxygen/Doxylocal
index 5c018991..220d9233 100644
--- a/doc/doxygen/Doxylocal
+++ b/doc/doxygen/Doxylocal
@@ -10,6 +10,7 @@ HIDE_SCOPE_NAMES       = YES
 HIDE_UNDOC_CLASSES     = NO
 INTERNAL_DOCS          = NO
 MARKDOWN_SUPPORT       = YES
+GENERATE_XML           = YES
 
 EXCLUDE_SYMBOLS        = AMDiS::Impl \
                          AMDiS::Math::Impl_ \
@@ -30,6 +31,7 @@ PREDEFINED            += HAVE_UMFPACK \
 
 INPUT                 += @top_srcdir@/src/amdis \
                          @top_srcdir@/src/amdis/common \
+                         @top_srcdir@/src/amdis/functions \
                          @top_srcdir@/src/amdis/gridfunctions \
                          @top_srcdir@/src/amdis/linearalgebra \
                          @top_srcdir@/src/amdis/linearalgebra/mtl \
@@ -47,7 +49,8 @@ INPUT                 += @top_srcdir@/src/amdis \
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
 
 EXCLUDE               += @top_srcdir@/src/amdis/linearalgebra/eigen \
-                         @top_srcdir@/src/amdis/linearalgebra/istl
+                         @top_srcdir@/src/amdis/linearalgebra/istl \
+                         @top_srcdir@/src/amdis/linearalgebra/petsc
 
 # The EXAMPLE_PATH tag can be used to specify one or more files or
 # directories that contain example code fragments that are included (see
diff --git a/src/amdis/BiLinearForm.hpp b/src/amdis/BiLinearForm.hpp
index d3864d6d..f7d3b8e2 100644
--- a/src/amdis/BiLinearForm.hpp
+++ b/src/amdis/BiLinearForm.hpp
@@ -20,14 +20,12 @@ namespace AMDiS
    * \tparam CB  Basis of matrix columns
    * \tparam T   Coefficient type to store in the matrix
    **/
-  template <class RB, class CB, class T = double>
+  template <class RB, class CB, class T = double, class Traits = BackendTraits<RB,T>>
   class BiLinearForm
-      : public MatrixBase<RB,CB,MatrixBackend<BackendTraits<RB,T>>>
+      : public MatrixFacade<T, typename Traits::SparsityPattern, Traits::template MatrixImpl>
   {
     using Self = BiLinearForm;
-    using Traits = BackendTraits<RB,T>;
-    using Backend = MatrixBackend<Traits>;
-    using Super = MatrixBase<RB,CB,Backend>;
+    using Super = MatrixFacade<T, typename Traits::SparsityPattern, Traits::template MatrixImpl>;
 
   public:
     /// The type of the finite element space / basis of the row
@@ -47,23 +45,21 @@ namespace AMDiS
   public:
     /// Constructor. Wraps the reference into a non-destroying shared_ptr or moves the basis into
     /// a new shared_ptr.
-    template <class RB_, class CB_>
-    BiLinearForm(RB_&& rowBasis, CB_&& colBasis)
-      : Super(FWD(rowBasis), FWD(colBasis))
+    BiLinearForm(std::shared_ptr<RB> const& rowBasis, std::shared_ptr<CB> const& colBasis)
+      : Super(*rowBasis, *colBasis)
+      , rowBasis_(rowBasis)
+      , colBasis_(colBasis)
     {
-      operators_.init(*Super::rowBasis(), *Super::colBasis());
-    }
-
-    /// Prepare the matrix for insertion. Clears all the entries.
-    void init(SymmetryStructure symmetry = SymmetryStructure::unknown)
-    {
-      Super::init(symmetry);
+      operators_.init(*rowBasis, *colBasis);
 
-      auto const rowSize = this->rowBasis()->localView().maxSize();
-      auto const colSize = this->colBasis()->localView().maxSize();
+      auto const rowSize = rowBasis->localView().maxSize();
+      auto const colSize = colBasis->localView().maxSize();
       elementMatrix_.resize(rowSize, colSize);
     }
 
+    std::shared_ptr<RowBasis const> const& rowBasis() const { return rowBasis_; }
+    std::shared_ptr<ColBasis const> const& colBasis() const { return colBasis_; }
+
     /// \brief Associate a local operator with this BiLinearForm
     /**
      * Stores an operator in a list that gets assembled during a call to \ref assemble().
@@ -118,6 +114,9 @@ namespace AMDiS
 
     /// List of operators associated to row/col node
     MatrixOperators<RowBasis,ColBasis,ElementMatrix> operators_;
+
+    std::shared_ptr<RowBasis const> rowBasis_;
+    std::shared_ptr<ColBasis const> colBasis_;
   };
 
 
diff --git a/src/amdis/BiLinearForm.inc.hpp b/src/amdis/BiLinearForm.inc.hpp
index 3e66984c..83cd7fb3 100644
--- a/src/amdis/BiLinearForm.inc.hpp
+++ b/src/amdis/BiLinearForm.inc.hpp
@@ -9,9 +9,9 @@
 
 namespace AMDiS {
 
-template <class RB, class CB, class T>
+template <class RB, class CB, class T, class Traits>
   template <class ContextTag, class Expr, class RowTreePath, class ColTreePath>
-void BiLinearForm<RB,CB,T>::
+void BiLinearForm<RB,CB,T,Traits>::
 addOperator(ContextTag contextTag, Expr const& expr,
             RowTreePath row, ColTreePath col)
 {
@@ -24,16 +24,16 @@ addOperator(ContextTag contextTag, Expr const& expr,
   auto j = child(this->colBasis()->localView().tree(), makeTreePath(col));
 
   using LocalContext = typename ContextTag::type;
-  using Traits = DefaultAssemblerTraits<LocalContext, ElementMatrix>;
+  using Tr = DefaultAssemblerTraits<LocalContext, ElementMatrix>;
   auto op = makeLocalOperator<LocalContext>(expr, this->rowBasis()->gridView());
-  auto localAssembler = makeUniquePtr(makeAssembler<Traits>(std::move(op), i, j));
+  auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), i, j));
 
   operators_[i][j].push(contextTag, std::move(localAssembler));
 }
 
 
-template <class RB, class CB, class T>
-void BiLinearForm<RB,CB,T>::
+template <class RB, class CB, class T, class Traits>
+void BiLinearForm<RB,CB,T,Traits>::
 assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView)
 {
   elementMatrix_.resize(rowLocalView.size(), colLocalView.size());
@@ -58,8 +58,8 @@ assemble(RowLocalView const& rowLocalView, ColLocalView const& colLocalView)
 }
 
 
-template <class RB, class CB, class T>
-void BiLinearForm<RB,CB,T>::
+template <class RB, class CB, class T, class Traits>
+void BiLinearForm<RB,CB,T,Traits>::
 assemble(SymmetryStructure symmetry)
 {
   auto rowLocalView = this->rowBasis()->localView();
diff --git a/src/amdis/DOFVector.hpp b/src/amdis/DOFVector.hpp
index f70b4d91..1dc708b9 100644
--- a/src/amdis/DOFVector.hpp
+++ b/src/amdis/DOFVector.hpp
@@ -33,38 +33,40 @@ namespace AMDiS
   /**
    * \tparam GB  Basis of the vector
    * \tparam T   Type of the coefficients
+   * \tparam TraitsType  Collection of parameter for the linear-algebra backend
    **/
-  template <class GB, class T = double>
+  template <class GB, class T = double, class TraitsType = BackendTraits<GB,T>>
   class DOFVector
-      : public VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>
+      : public VectorFacade<T, TraitsType::template VectorImpl>
       , private Observer<event::preAdapt>
       , private Observer<event::adapt>
       , private Observer<event::postAdapt>
   {
     using Self = DOFVector;
-    using Super = VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>;
+    using Coefficients = VectorFacade<T, TraitsType::template VectorImpl>;
 
   public:
-    using Backend = VectorBackend<BackendTraits<GB,T>>;
-
     using GlobalBasis = GB;
 
     /// The index/size - type
     using size_type  = typename GlobalBasis::size_type;
 
     /// The type of the elements of the DOFVector
-    using value_type = typename Backend::value_type;
+    using value_type = T;
 
     /// Wrapper for the implementation of the transfer of data during grid adaption
     using DataTransfer = DataTransferWrapper<Self>;
 
+    /// Collection of parameter for the linear-algebra backend
+    using Traits = TraitsType;
+
   public:
     /// Constructor. Stores the shared_ptr of the basis and creates a new DataTransfer.
     DOFVector(std::shared_ptr<GB> const& basis,
               DataTransferOperation op = DataTransferOperation::INTERPOLATE)
-      : Super(basis)
+      : Coefficients(*basis)
       , Observer<event::preAdapt>(basis->gridView().grid())
-      , Observer<event::adapt>(*basis)
+      , Observer<event::adapt>(basis)
       , Observer<event::postAdapt>(basis->gridView().grid())
       , dataTransfer_(op, basis)
       , basis_(basis)
@@ -83,19 +85,20 @@ namespace AMDiS
       : DOFVector(Dune::wrap_or_move(FWD(basis)), op)
     {}
 
+    std::shared_ptr<GlobalBasis const> const& basis() const { return basis_; }
 
     template <class TreePath = RootTreePath>
     auto child(TreePath const& path = {})
     {
       auto&& tp = makeTreePath(path);
-      return makeDiscreteFunction(*this, tp);
+      return makeDiscreteFunction(coefficients(), *basis_, tp);
     }
 
     template <class TreePath = RootTreePath>
     auto child(TreePath const& path = {}) const
     {
       auto&& tp = makeTreePath(path);
-      return makeDiscreteFunction(*this, tp);
+      return makeDiscreteFunction(coefficients(), *basis_, tp);
     }
 
 
@@ -103,7 +106,7 @@ namespace AMDiS
     /// reference to this DOFVector in the expression.
     /// See \ref DiscreteFunction::interpolate_noalias
     template <class Expr, class Tag = tag::average>
-    void interpolate_noalias(Expr&& expr, Tag strategy)
+    void interpolate_noalias(Expr&& expr, Tag strategy = {})
     {
       child().interpolate_noalias(FWD(expr), strategy);
     }
@@ -111,7 +114,7 @@ namespace AMDiS
     /// Interpolation of GridFunction to DOFVector.
     /// See \ref DiscreteFunction::interpolate
     template <class Expr, class Tag = tag::average>
-    void interpolate(Expr&& expr, Tag strategy)
+    void interpolate(Expr&& expr, Tag strategy = {})
     {
       child().interpolate(FWD(expr), strategy);
     }
@@ -126,6 +129,16 @@ namespace AMDiS
     }
 
 
+    Coefficients const& coefficients() const 
+    {
+      return static_cast<Coefficients const&>(*this);
+    }
+
+    Coefficients& coefficients() 
+    {
+      return static_cast<Coefficients&>(*this);
+    }
+
     /// Write DOFVector to file
     void backup(std::string const& filename);
 
@@ -192,7 +205,7 @@ namespace AMDiS
     /// to \ref DataTransferOperation::INTERPOLATE.
     DataTransfer dataTransfer_;
 
-    std::shared_ptr<GB> basis_;
+    std::shared_ptr<GlobalBasis const> basis_;
   };
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
@@ -218,6 +231,20 @@ namespace AMDiS
     return {FWD(basis), op};
   }
 
+  /// A Generator for a mutable \ref DiscreteFunction
+  template <class GB, class T, class Path = RootTreePath>
+  auto makeDiscreteFunction(DOFVector<GB,T>& dofVec, Path const& path = {})
+  {
+    return dofVec.child(path);
+  }
+
+  /// A Generator for a mutable \ref DiscreteFunction
+  template <class GB, class T, class Path = RootTreePath>
+  auto makeDiscreteFunction(DOFVector<GB,T> const& dofVec, Path const& path = {})
+  {
+    return dofVec.child(path);
+  }
+
 } // end namespace AMDiS
 
 #include <amdis/DOFVector.inc.hpp>
diff --git a/src/amdis/DOFVector.inc.hpp b/src/amdis/DOFVector.inc.hpp
index fd940199..eb02fe3f 100644
--- a/src/amdis/DOFVector.inc.hpp
+++ b/src/amdis/DOFVector.inc.hpp
@@ -10,8 +10,8 @@
 
 namespace AMDiS {
 
-template <class GB, class B>
-void DOFVector<GB,B>::
+template <class GB, class T, class Traits>
+void DOFVector<GB,T,Traits>::
 backup(std::string const& filename)
 {
   std::ofstream out(filename, std::ios::binary);
@@ -35,8 +35,8 @@ backup(std::string const& filename)
 }
 
 
-template <class GB, class B>
-void DOFVector<GB,B>::
+template <class GB, class T, class Traits>
+void DOFVector<GB,T,Traits>::
 restore(std::string const& filename)
 {
   std::ifstream in(filename, std::ios::binary);
diff --git a/src/amdis/DataTransfer.inc.hpp b/src/amdis/DataTransfer.inc.hpp
index bf84ccfc..f9434fb8 100644
--- a/src/amdis/DataTransfer.inc.hpp
+++ b/src/amdis/DataTransfer.inc.hpp
@@ -82,7 +82,7 @@ preAdapt(C const& coeff, bool mightCoarsen)
   auto maxLevel = gv.grid().maxLevel();
   using std::sqrt;
   typename Grid::ctype const checkInsideTolerance = sqrt(std::numeric_limits<typename Grid::ctype>::epsilon());
-  for (auto const& e : elements(gv, typename C::Backend::Traits::PartitionSet{}))
+  for (auto const& e : elements(gv, typename C::Traits::PartitionSet{}))
   {
     auto father = e;
     while (father.mightVanish() && father.hasFather())
@@ -162,7 +162,7 @@ void DataTransfer<C,B>::adapt(C& coeff)
 
   mapper_.update();
   std::vector<bool> finished(mapper_.size(), false);
-  for (const auto& e : elements(gv, typename C::Backend::Traits::PartitionSet{}))
+  for (const auto& e : elements(gv, typename C::Traits::PartitionSet{}))
   {
     auto index = mapper_.index(e);
     if (finished[index])
diff --git a/src/amdis/LinearAlgebra.hpp b/src/amdis/LinearAlgebra.hpp
index f8c5d4de..d1dda9f1 100644
--- a/src/amdis/LinearAlgebra.hpp
+++ b/src/amdis/LinearAlgebra.hpp
@@ -37,7 +37,7 @@
 
 #endif
 
-#include <amdis/linearalgebra/MatrixBase.hpp>
-#include <amdis/linearalgebra/VectorBase.hpp>
+#include <amdis/linearalgebra/MatrixFacade.hpp>
+#include <amdis/linearalgebra/VectorFacade.hpp>
 #include <amdis/linearalgebra/LinearSolver.hpp>
 #include <amdis/linearalgebra/SolverInfo.hpp>
diff --git a/src/amdis/LinearForm.hpp b/src/amdis/LinearForm.hpp
index 8601d904..78d04718 100644
--- a/src/amdis/LinearForm.hpp
+++ b/src/amdis/LinearForm.hpp
@@ -17,24 +17,20 @@ namespace AMDiS
    *
    * \tparam GB  Basis of the vector
    * \tparam T   Coefficient type to store in the vector
+   * \tparam Traits  Collection of parameter for the linear-algebra backend
    **/
-  template <class GB, class T = double>
+  template <class GB, class T = double, class Traits = BackendTraits<GB,T>>
   class LinearForm
-      : public VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>
+      : public VectorFacade<T, Traits::template VectorImpl>
   {
-    using Super = VectorBase<GB, VectorBackend<BackendTraits<GB,T>>>;
+    using Super = VectorFacade<T, Traits::template VectorImpl>;
     using Self = LinearForm;
 
   public:
-    using Backend = VectorBackend<BackendTraits<GB,T>>;
-
     /// The type of the functionspace basis associated to this linearform
     using GlobalBasis = GB;
     using LocalView = typename GlobalBasis::LocalView;
 
-    /// A traits class collecting several parameters of the linear algebra backend
-    using Traits = typename Backend::Traits;
-
     /// The type of the elements of the DOFVector
     using CoefficientType = typename Traits::CoefficientType;
 
@@ -43,24 +39,18 @@ namespace AMDiS
 
   public:
     /// Constructor. Stores the shared_ptr of the basis and creates a new DataTransfer.
-    template <class GB_,
-      Dune::disableCopyMove<Self, GB_> = 0>
-    explicit LinearForm(GB_&& basis)
-      : Super(FWD(basis))
+    explicit LinearForm(std::shared_ptr<GB> const& basis)
+      : Super(*basis)
+      , basis_(basis)
     {
-      operators_.init(*Super::basis());
-    }
+      operators_.init(*basis);
 
-    /// Prepare the LinearForm for insertion of values, finish the insertion with
-    /// \ref finish().
-    void init(bool clear)
-    {
-      Super::init(clear);
-
-      auto const localSize = this->basis()->localView().maxSize();
+      auto const localSize = basis->localView().maxSize();
       elementVector_.resize(localSize);
     }
 
+    std::shared_ptr<GlobalBasis const> const& basis() const { return basis_; }
+
     /// \brief Associate a local operator with this LinearForm
     /**
      * Stores an operator in a list that gets assembled during a call to \ref assemble().
@@ -112,6 +102,8 @@ namespace AMDiS
 
     /// List of operators associated to nodes, filled in \ref addOperator().
     VectorOperators<GlobalBasis,ElementVector> operators_;
+
+    std::shared_ptr<GlobalBasis const> basis_;
   };
 
 
diff --git a/src/amdis/LinearForm.inc.hpp b/src/amdis/LinearForm.inc.hpp
index cd39cb80..5277f410 100644
--- a/src/amdis/LinearForm.inc.hpp
+++ b/src/amdis/LinearForm.inc.hpp
@@ -10,9 +10,9 @@
 
 namespace AMDiS {
 
-template <class GB, class B>
+template <class GB, class T, class Traits>
   template <class ContextTag, class Expr, class TreePath>
-void LinearForm<GB,B>::
+void LinearForm<GB,T,Traits>::
 addOperator(ContextTag contextTag, Expr const& expr, TreePath path)
 {
   static_assert( Concepts::PreTreePath<TreePath>,
@@ -21,16 +21,16 @@ addOperator(ContextTag contextTag, Expr const& expr, TreePath path)
   auto i = child(this->basis()->localView().tree(), makeTreePath(path));
 
   using LocalContext = typename ContextTag::type;
-  using Traits = DefaultAssemblerTraits<LocalContext, ElementVector>;
+  using Tr = DefaultAssemblerTraits<LocalContext, ElementVector>;
   auto op = makeLocalOperator<LocalContext>(expr, this->basis()->gridView());
-  auto localAssembler = makeUniquePtr(makeAssembler<Traits>(std::move(op), i));
+  auto localAssembler = makeUniquePtr(makeAssembler<Tr>(std::move(op), i));
 
   operators_[i].push(contextTag, std::move(localAssembler));
 }
 
 
-template <class GB, class B>
-void LinearForm<GB,B>::
+template <class GB, class T, class Traits>
+void LinearForm<GB,T,Traits>::
 assemble(typename GB::LocalView const& localView)
 {
   elementVector_.resize(localView.size());
@@ -53,8 +53,8 @@ assemble(typename GB::LocalView const& localView)
 }
 
 
-template <class GB, class B>
-void LinearForm<GB,B>::
+template <class GB, class T, class Traits>
+void LinearForm<GB,T,Traits>::
 assemble()
 {
   auto localView = this->basis()->localView();
diff --git a/src/amdis/Observer.hpp b/src/amdis/Observer.hpp
index b031e431..865e5936 100644
--- a/src/amdis/Observer.hpp
+++ b/src/amdis/Observer.hpp
@@ -1,14 +1,15 @@
 #pragma once
 
 #include <algorithm>
-#include <list>
 #include <memory>
+#include <set>
 #include <type_traits>
 
+#include <dune/common/shared_ptr.hh>
 #include <dune/common/typeutilities.hh>
 
 #include <amdis/common/ConceptsBase.hpp>
-#include <amdis/Output.hpp>
+#include <amdis/common/Index.hpp>
 
 namespace AMDiS
 {
@@ -75,19 +76,17 @@ namespace AMDiS
     /// Attach a new observer that gets called on \ref notify
     void attach(ObserverInterface<Event>* o)
     {
-      observers_.push_back(o);
+      observers_.insert(o);
     }
 
     /// Detaches the passed observer from the list, if stored.
     void detach(ObserverInterface<Event>* o)
     {
-      auto it = std::find(observers_.begin(), observers_.end(), o);
-      if (it != observers_.end())
-        observers_.erase(it);
+      observers_.erase(o);
     }
 
   private:
-    std::list<ObserverInterface<Event>*> observers_;
+    std::set<ObserverInterface<Event>*> observers_;
   };
 
 
@@ -98,17 +97,23 @@ namespace AMDiS
   {
   public:
     template <class Notifier>
-    Observer(Notifier const& notifier)
-      : notifier_(const_cast<Notifier*>(&notifier))
+    Observer(std::shared_ptr<Notifier> notifier)
+      : notifier_(std::const_pointer_cast<std::remove_const_t<Notifier>>(std::move(notifier)))
     {
       notifier_->attach(this);
     }
 
+    template <class Notifier,
+      class = void_t<decltype(std::declval<std::remove_const_t<Notifier>>().notify(std::declval<Event>()))> >
+    Observer(Notifier& notifier)
+      : Observer(Dune::stackobject_to_shared_ptr(notifier))
+    {}
+
     /// Destructor, detaches from the notifier
     virtual ~Observer()
     {
-      assert(notifier_);
-      notifier_->detach(this);
+      if (notifier_)
+        notifier_->detach(this);
     }
 
     /// Copy constructor. Attaches this to the copied notifier
@@ -121,23 +126,11 @@ namespace AMDiS
     /// Copy-assignment operator, copies the notifier and attaches this.
     Observer& operator=(Observer const& other)
     {
-      notifier_ = other.notifier_;
-      notifier_->attach(this);
-      return *this;
-    }
-
-    /// Move assignment operator, implemented in terms of the move
-    /// assignment operator
-    Observer(Observer&& other)
-    {
-      *this = std::move(other);
-    }
-
-    /// Move-assignment operator, copies the notifier and attaches this.
-    Observer& operator=(Observer&& other)
-    {
-      notifier_ = other.notifier_;
-      notifier_->attach(this);
+      if (&other != this) {
+        notifier_->detach(this);
+        notifier_ = other.notifier_;
+        notifier_->attach(this);
+      }
       return *this;
     }
 
@@ -155,7 +148,31 @@ namespace AMDiS
     virtual void updateImpl(Event e, Tags...) = 0;
 
   private:
-    Notifier<Event>* notifier_ = nullptr;
+    std::shared_ptr<Notifier<Event>> notifier_ = nullptr;
   };
 
+
+  namespace Impl 
+  {
+    template <class Event, class Tags>
+    class ObserverSequenceImpl;
+
+    /// Combination of multiple observers of the same event but with different tags
+    template <class Event, std::size_t... Is>
+    class ObserverSequenceImpl<Event, std::index_sequence<Is...>>
+        : private Observer<Event,index_t<Is>>...
+    {
+    public:
+      template <class... Notifiers,
+        REQUIRES(sizeof...(Notifiers) == sizeof...(Is))>
+      ObserverSequenceImpl(Notifiers&&... notifiers)
+        : Observer<Event,index_t<Is>>(FWD(notifiers))...
+      {}
+    };
+
+  } // end namespace Impl
+
+  template <class Event, std::size_t N>
+  using ObserverSequence = Impl::ObserverSequenceImpl<Event, std::make_index_sequence<N>>;
+
 } // end namespace AMDiS
diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp
index ab4699a6..b83915b6 100644
--- a/src/amdis/ProblemStat.inc.hpp
+++ b/src/amdis/ProblemStat.inc.hpp
@@ -382,8 +382,8 @@ solve(AdaptInfo& adaptInfo, bool createMatrixData, bool storeMatrixData)
   solverInfo.setStoreMatrixData(storeMatrixData);
 
   solution_->resize();
-  linearSolver_->solve(systemMatrix_->backend().matrix(), solution_->backend().vector(),
-                       rhs_->backend().vector(), globalBasis_->communicator(), solverInfo);
+  linearSolver_->solve(systemMatrix_->impl().matrix(), solution_->impl().vector(),
+                       rhs_->impl().vector(), globalBasis_->communicator(), solverInfo);
 
   if (solverInfo.info() > 0) {
     msg("solution of discrete system needed {} seconds", t.elapsed());
diff --git a/src/amdis/functions/CMakeLists.txt b/src/amdis/functions/CMakeLists.txt
index 73697b63..c8ef3913 100644
--- a/src/amdis/functions/CMakeLists.txt
+++ b/src/amdis/functions/CMakeLists.txt
@@ -6,4 +6,5 @@ install(FILES
     NodeIndices.hpp
     Nodes.hpp
     ParallelGlobalBasis.hpp
+    SizeInfo.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/functions)
diff --git a/src/amdis/functions/Interpolate.hpp b/src/amdis/functions/Interpolate.hpp
index dbec178c..e7f23a8f 100644
--- a/src/amdis/functions/Interpolate.hpp
+++ b/src/amdis/functions/Interpolate.hpp
@@ -16,6 +16,7 @@
 #include <amdis/functions/HierarchicNodeToRangeMap.hpp>
 #include <amdis/functions/NodeIndices.hpp>
 #include <amdis/gridfunctions/GridFunction.hpp>
+#include <amdis/linearalgebra/Traits.hpp>
 #include <amdis/operations/Assigner.hpp>
 #include <amdis/typetree/Traversal.hpp>
 
@@ -39,7 +40,7 @@ namespace AMDiS
 
       // set vector to zero at subtree
       if (! std::is_same<Assign, Assigner::assign>::value) {
-        for (const auto& e : elements(basis.gridView(), typename Vec::Backend::Traits::PartitionSet{}))
+        for (const auto& e : elements(basis.gridView(), typename BackendTraits<B>::PartitionSet{}))
         {
           localView.bind(e);
           auto&& subTree = Dune::TypeTree::child(localView.tree(), treePath);
@@ -54,7 +55,7 @@ namespace AMDiS
 
       vector.init(false);
       counter.init(true); // set to zero
-      for (const auto& e : elements(basis.gridView(), typename Vec::Backend::Traits::PartitionSet{}))
+      for (const auto& e : elements(basis.gridView(), typename BackendTraits<B>::PartitionSet{}))
       {
         localView.bind(e);
         lf.bind(e);
@@ -68,7 +69,7 @@ namespace AMDiS
           auto&& fe = node.finiteElement();
           std::size_t feSize = fe.localBasis().size();
 
-          auto bitVecRange = mappedRangeView(Dune::range(feSize), [&](auto i) -> bool {
+          auto bitVecRange = mappedRangeView(Dune::range(feSize), [&](std::size_t i) -> bool {
             return bitVec[localView.index(node.localIndex(i))];
           });
 
diff --git a/src/amdis/functions/NodeIndices.hpp b/src/amdis/functions/NodeIndices.hpp
index 98fd9463..3c17182e 100644
--- a/src/amdis/functions/NodeIndices.hpp
+++ b/src/amdis/functions/NodeIndices.hpp
@@ -16,8 +16,8 @@ namespace AMDiS
     static_assert(Dune::models<Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>(), "");
     static_assert(Dune::models<Concept::BasisTree<typename LocalView::GridView>, Node>(), "");
 
-    return mappedRangeView(Dune::range(node.size()), [&](std::size_t j) -> std::size_t {
-      return flatMultiIndex(localView.index(node.localIndex(j)));
+    return mappedRangeView(Dune::range(node.size()), [&](std::size_t j) -> typename LocalView::MultiIndex {
+      return localView.index(node.localIndex(j));
     });
   }
 
@@ -28,8 +28,8 @@ namespace AMDiS
     using namespace Dune::Functions;
     static_assert(Dune::models<Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>(), "");
 
-    return mappedRangeView(Dune::range(localView.size()), [&](std::size_t i) -> std::size_t {
-      return flatMultiIndex(localView.index(i));
+    return mappedRangeView(Dune::range(localView.size()), [&](std::size_t i) -> typename LocalView::MultiIndex {
+      return localView.index(i);
     });
   }
 
diff --git a/src/amdis/functions/ParallelGlobalBasis.hpp b/src/amdis/functions/ParallelGlobalBasis.hpp
index 0837be09..8e219428 100644
--- a/src/amdis/functions/ParallelGlobalBasis.hpp
+++ b/src/amdis/functions/ParallelGlobalBasis.hpp
@@ -101,11 +101,15 @@ namespace AMDiS
      *  This will create a new ParallellGlobalBasis. The pre-basis is copied from the constructor
      *  argument and a new communication object is built.
      */
-    // TODO(FM): Replace explicit type with concept
     ParallelGlobalBasis(Dune::Functions::DefaultGlobalBasis<PB>&& from)
       : ParallelGlobalBasis(std::string(""), from.gridView().grid(), from.preBasis())
     {}
 
+    /// Copy constructor
+    ParallelGlobalBasis(ParallelGlobalBasis const&) = delete;
+
+    /// Move constructor
+    ParallelGlobalBasis(ParallelGlobalBasis&&) = default;
 
   public:
 
diff --git a/src/amdis/functions/SizeInfo.hpp b/src/amdis/functions/SizeInfo.hpp
new file mode 100644
index 00000000..5f1d2777
--- /dev/null
+++ b/src/amdis/functions/SizeInfo.hpp
@@ -0,0 +1,89 @@
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <iterator>
+#include <utility>
+#include <vector>
+
+#include <dune/common/typetraits.hh>
+
+namespace AMDiS
+{
+  /// \brief Type-erased wrapper around size providers
+  class SizeInfo
+  {
+  public:
+    using size_type = std::size_t;
+
+    // The SizePrefix can be created from any container with begin-end iterators.
+    // It just stores a copy of the given prefix in a `std::vector` and copies its 
+    // content back on request of the `SizeProvider::size` method, where the actual
+    // `SizeProvider::SizePrefix` is known.
+    class SizePrefix
+        : public std::vector<size_type>
+    {
+      using Super = std::vector<size_type>;
+
+    public:
+      SizePrefix() = default;
+
+      // Constructor copies the content of the passed container to the internal storage
+      template <class Container,
+        Dune::disableCopyMove<SizePrefix, Container> = 0,
+        Dune::disableCopyMove<Super, Container> = 0>
+      SizePrefix(Container const& container)
+        : Super(container.begin(), container.end())
+      {}
+
+      using Super::Super;
+
+      friend std::ostream& operator<<(std::ostream& out, SizePrefix const& prefix)
+      {
+        std::copy(prefix.begin(), prefix.end(), std::ostream_iterator<size_type>(out, " "));
+        return out;
+      }
+    };
+
+  public:
+    /// Store the passed `Dune::SizeInfo` object in a type-erased manner
+    /// by providing an own `SizePrefix` and `size_type` type, that can be 
+    /// filled from the actual objects.
+    template <class SizeProvider,
+      class = void_t<decltype(std::declval<SizeProvider>()(std::declval<typename SizeProvider::SizePrefix>()))> >
+    explicit SizeInfo(SizeProvider const& provider)
+      : size_([provider](SizePrefix const& prefix) -> size_type {
+          typename SizeProvider::SizePrefix sizePrefix;
+          sizePrefix.resize(prefix.size());
+          std::copy(prefix.begin(), prefix.end(), sizePrefix.begin());
+          return provider(sizePrefix);
+        })
+      , dimension_([provider]() -> size_type {
+          return size_type(provider);
+        })
+    {}
+
+    /// Return number possible values for next position in multi index
+    size_type size(SizePrefix prefix) const 
+    {
+      return size_(prefix);
+    }
+
+    /// Return number possible values for next position in multi index
+    size_type operator()(SizePrefix prefix) const 
+    {
+      return size_(prefix);
+    }
+
+    /// Return the total dimension of the associated size-provider (basis)
+    operator size_type() const 
+    {
+      return dimension_();
+    }
+
+  private:
+    std::function<size_type(SizePrefix const&)> size_;
+    std::function<size_type()> dimension_;
+  };
+}
\ No newline at end of file
diff --git a/src/amdis/gridfunctions/DiscreteFunction.hpp b/src/amdis/gridfunctions/DiscreteFunction.hpp
index ea97c780..99298277 100644
--- a/src/amdis/gridfunctions/DiscreteFunction.hpp
+++ b/src/amdis/gridfunctions/DiscreteFunction.hpp
@@ -16,71 +16,137 @@
 
 namespace AMDiS
 {
-  template <class GB, class VT>
-  class DOFVector;
-  
   /// \class DiscreteFunction
   /// \brief A view on a subspace of a \ref DOFVector
   /**
   * \ingroup GridFunctions
   *
-  * \tparam GB  Type of the global basis
-  * \tparam VT  Coefficient type of the DOFVector
-  * \tparam TP  A realization of \ref Dune::TypeTree::HybridTreePath
-  * \tparam is_const  Specifies whether a const or mutable view is implemented.
+  * \tparam Coeff     Const or mutable coefficient type of the DOFVector
+  * \tparam GB        Thy type of the global basis
+  * \tparam TreePath  A realization of \ref Dune::TypeTree::HybridTreePath
   *
   * **Requirements:**
   * - GB models \ref Dune::Functions::Concept::GlobalBasis
   **/
-  template <class GB, class VT, class TP, bool is_const>
+  template <class Coeff, class GB, class TreePath = Dune::TypeTree::HybridTreePath<>>
   class DiscreteFunction;
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  // Deduction guide for DiscreteFunction class
-  template <class GB, class VT>
-  DiscreteFunction(DOFVector<GB, VT> const& dofVector)
-    -> DiscreteFunction<GB, VT, Dune::TypeTree::HybridTreePath<>, true>;
-
-  template <class GB, class VT>
-  DiscreteFunction(DOFVector<GB, VT>& dofVector)
-    -> DiscreteFunction<GB, VT, Dune::TypeTree::HybridTreePath<>, false>;
+  template <class Coeff, class GB, class TreePath = Dune::TypeTree::HybridTreePath<>>
+  DiscreteFunction(Coeff&, GB const&, TreePath = {})
+    -> DiscreteFunction<Coeff, GB, TreePath>;
 #endif
 
-
-  /// A Generator for a const \ref DiscreteFunction
-  template <class GlobalBasis, class ValueType,
-            class PreTreePath = Dune::TypeTree::HybridTreePath<>>
-  auto makeDiscreteFunction(DOFVector<GlobalBasis, ValueType> const& dofVector,
-                            PreTreePath const& preTreePath = {})
+  /// A Generator for a mutable \ref DiscreteFunction
+  template <class Coeff, class GB, class Path,
+    class = void_t<decltype(std::declval<GB>().localView())> >
+  auto makeDiscreteFunction(Coeff& coefficients, GB const& basis, Path const& path)
   {
-    auto treePath = makeTreePath(preTreePath);
-    return DiscreteFunction<GlobalBasis, ValueType, decltype(treePath), true>{dofVector, treePath};
+    auto treePath = makeTreePath(path);
+    return DiscreteFunction<Coeff, GB, decltype(treePath)>{coefficients, basis, treePath};
   }
 
-  /// A Generator for a mutable \ref DiscreteFunction
-  template <class GlobalBasis, class ValueType,
-            class PreTreePath = Dune::TypeTree::HybridTreePath<>>
-  auto makeDiscreteFunction(DOFVector<GlobalBasis, ValueType>& dofVector,
-                            PreTreePath const& preTreePath = {})
+
+  /// A mutable view on the subspace of a DOFVector, \relates DiscreteFunction
+  template <class Coeff, class GB, class TreePath>
+  class DiscreteFunction
+      : public DiscreteFunction<Coeff const,GB,TreePath>
   {
-    auto treePath = makeTreePath(preTreePath);
-    return DiscreteFunction<GlobalBasis, ValueType, decltype(treePath), false>{dofVector, treePath};
-  }
+    using Self = DiscreteFunction<Coeff,GB,TreePath>;
+    using Super = DiscreteFunction<Coeff const,GB,TreePath>;
+
+    using Coefficients = Coeff;
+    using GlobalBasis = GB;
+    using ValueType = typename Coeff::value_type;
 
+  public:
+    /// Constructor. Stores a pointer to the mutable `dofvector`.
+    DiscreteFunction(Coefficients& dofVector, GlobalBasis const& basis, TreePath const& treePath = {})
+      : Super(dofVector, basis, treePath)
+      , mutableCoeff_(&dofVector)
+    {}
+
+  public:
+    /// \brief Interpolation of GridFunction to DOFVector, assuming that there is no
+    /// reference to this DOFVector in the expression.
+    /**
+     * **Example:**
+     * ```
+     * auto v = makeDiscreteFunction(prob.solutionVector(),0);
+     * v.interpolate_noalias([](auto const& x) { return x[0]; });
+     * ```
+     **/
+    template <class Expr, class Tag = tag::average>
+    void interpolate_noalias(Expr&& expr, Tag strategy = {});
 
+    /// \brief Interpolation of GridFunction to DOFVector
+    /**
+     * **Example:**
+     * ```
+     * auto v = makeDiscreteFunction(prob.solutionVector(),0);
+     * v.interpolate(v + [](auto const& x) { return x[0]; });
+     * ```
+     * Allows to have a reference to the DOFVector in the expression, e.g. as
+     * \ref DiscreteFunction or \ref gradientAtQP() of a DiscreteFunction.
+     **/
+    template <class Expr, class Tag = tag::average>
+    void interpolate(Expr&& expr, Tag strategy = {});
+
+    /// \brief Interpolation of GridFunction to DOFVector, alias to \ref interpolate()
+    template <class Expr>
+    Self& operator<<(Expr&& expr)
+    {
+      interpolate(FWD(expr));
+      return *this;
+    }
+
+    /// \brief interpolate `(*this) + expr` to DOFVector
+    template <class Expr>
+    Self& operator+=(Expr&& expr)
+    {
+      interpolate((*this) + expr);
+      return *this;
+    }
+
+    /// \brief interpolate `(*this) - expr` to DOFVector
+    template <class Expr>
+    Self& operator-=(Expr&& expr)
+    {
+      interpolate((*this) - expr);
+      return *this;
+    }
+
+    /// Return the mutable DOFVector
+    Coefficients& coefficients() { return *mutableCoeff_; }
+
+    /// Return the const DOFVector
+    using Super::coefficients;
+
+    template <class Path = RootTreePath>
+    auto child(Path const& path = {})
+    {
+      auto&& tp = makeTreePath(path);
+      return makeDiscreteFunction(*mutableCoeff_, this->basis(), cat(this->treePath_,tp));
+    }
+
+    using Super::child;
+
+  protected:
+    Coefficients* mutableCoeff_;
+  };
 
   /// A Const DiscreteFunction
-  template <class GB, class VT, class TP>
-  class DiscreteFunction<GB,VT,TP,true>
+  template <class Coeff, class GB, class TreePath>
+  class DiscreteFunction<Coeff const,GB,TreePath>
   {
   private:
+    using Coefficients = std::remove_const_t<Coeff>;
     using GlobalBasis = GB;
-    using TreePath = TP;
+    using ValueType = typename Coeff::value_type;
 
     using Tree = typename GlobalBasis::LocalView::Tree;
     using SubTree = typename Dune::TypeTree::ChildForTreePath<Tree, TreePath>;
     using NodeToRangeEntry = Dune::Functions::DefaultNodeToRangeMap<SubTree>;
-
     using GridView = typename GlobalBasis::GridView;
 
   public:
@@ -91,7 +157,7 @@ namespace AMDiS
     using Domain = typename EntitySet::GlobalCoordinate;
 
     /// Range type of this DiscreteFunction
-    using Range = RangeType_t<SubTree,VT>;
+    using Range = RangeType_t<SubTree,ValueType>;
 
     /// \brief This GridFunction has no derivative function, it can be created
     /// by \ref DiscreteGridFunction.
@@ -111,11 +177,12 @@ namespace AMDiS
 
   public:
     /// Constructor. Stores a pointer to the dofVector and a copy of the treePath.
-    DiscreteFunction(DOFVector<GB,VT> const& dofVector, TP const& treePath = {})
-      : dofVector_(&dofVector)
+    DiscreteFunction(Coefficients const& coefficients, GlobalBasis const& basis, TreePath const& treePath = {})
+      : coefficients_(&coefficients)
+      , basis_(&basis)
       , treePath_(treePath)
-      , entitySet_(dofVector.basis()->gridView())
-      , nodeToRangeEntry_(Dune::Functions::makeDefaultNodeToRangeMap(*dofVector.basis(), treePath))
+      , entitySet_(basis_->gridView())
+      , nodeToRangeEntry_(Dune::Functions::makeDefaultNodeToRangeMap(*basis_, treePath))
     {}
 
     /// \brief Evaluate DiscreteFunction in global coordinates. NOTE: expensive
@@ -134,9 +201,9 @@ namespace AMDiS
     }
 
     /// \brief Return global basis bound to the DOFVector
-    std::shared_ptr<GlobalBasis const> basis() const
+    GlobalBasis const& basis() const
     {
-      return dofVector_->basis();
+      return *basis_;
     }
 
     /// \brief Return treePath associated with this discrete function
@@ -146,114 +213,26 @@ namespace AMDiS
     }
 
     /// \brief Return const coefficient vector
-    DOFVector<GB,VT> const& coefficients() const
+    Coefficients const& coefficients() const
     {
-      return *dofVector_;
+      return *coefficients_;
     }
 
-    template <class TreePath = RootTreePath>
-    auto child(TreePath const& path = {}) const
+    template <class Path = RootTreePath>
+    auto child(Path const& path = {}) const
     {
       auto&& tp = makeTreePath(path);
-      return makeDiscreteFunction(*dofVector_, cat(this->treePath_,tp));
+      return makeDiscreteFunction(*coefficients_, *basis_, cat(this->treePath_,tp));
     }
 
   protected:
-    DOFVector<GB,VT> const* dofVector_;
+    Coefficients const* coefficients_;
+    GlobalBasis const* basis_;
     TreePath treePath_;
     EntitySet entitySet_;
     NodeToRangeEntry nodeToRangeEntry_;
   };
 
-
-
-  /// A mutable view on the subspace of a DOFVector, \relates DiscreteFunction
-  template <class GB, class VT, class TP>
-  class DiscreteFunction<GB,VT,TP,false>
-      : public DiscreteFunction<GB, VT, TP, true>
-  {
-    using Self = DiscreteFunction<GB, VT, TP, false>;
-    using Super = DiscreteFunction<GB, VT, TP, true>;
-
-    using GlobalBasis = GB;
-    using TreePath = TP;
-
-  public:
-    /// Constructor. Stores a pointer to the mutable `dofvector`.
-    DiscreteFunction(DOFVector<GB,VT>& dofVector, TP const& treePath = {})
-      : Super(dofVector, treePath)
-      , mutableDofVector_(&dofVector)
-    {}
-
-  public:
-    /// \brief Interpolation of GridFunction to DOFVector, assuming that there is no
-    /// reference to this DOFVector in the expression.
-    /**
-     * **Example:**
-     * ```
-     * auto v = makeDiscreteFunction(prob.solutionVector(),0);
-     * v.interpolate_noalias([](auto const& x) { return x[0]; });
-     * ```
-     **/
-    template <class Expr, class Tag = tag::average>
-    void interpolate_noalias(Expr&& expr, Tag strategy = {});
-
-    /// \brief Interpolation of GridFunction to DOFVector
-    /**
-     * **Example:**
-     * ```
-     * auto v = makeDiscreteFunction(prob.solutionVector(),0);
-     * v.interpolate(v + [](auto const& x) { return x[0]; });
-     * ```
-     * Allows to have a reference to the DOFVector in the expression, e.g. as
-     * \ref DiscreteFunction or \ref gradientAtQP() of a DiscreteFunction.
-     **/
-    template <class Expr, class Tag = tag::average>
-    void interpolate(Expr&& expr, Tag strategy = {});
-
-    /// \brief Interpolation of GridFunction to DOFVector, alias to \ref interpolate()
-    template <class Expr>
-    Self& operator<<(Expr&& expr)
-    {
-      interpolate(FWD(expr));
-      return *this;
-    }
-
-    /// \brief interpolate `(*this) + expr` to DOFVector
-    template <class Expr>
-    Self& operator+=(Expr&& expr)
-    {
-      interpolate((*this) + expr);
-      return *this;
-    }
-
-    /// \brief interpolate `(*this) - expr` to DOFVector
-    template <class Expr>
-    Self& operator-=(Expr&& expr)
-    {
-      interpolate((*this) - expr);
-      return *this;
-    }
-
-    /// Return the mutable DOFVector
-    DOFVector<GB,VT>& coefficients() { return *mutableDofVector_; }
-
-    /// Return the const DOFVector
-    using Super::coefficients;
-
-    template <class TreePath = RootTreePath>
-    auto child(TreePath const& path = {})
-    {
-      auto&& tp = makeTreePath(path);
-      return makeDiscreteFunction(*mutableDofVector_, cat(this->treePath_,tp));
-    }
-
-    using Super::child;
-
-  protected:
-    DOFVector<GB,VT>* mutableDofVector_;
-  };
-
 } // end namespace AMDiS
 
 #include "DiscreteLocalFunction.inc.hpp"
diff --git a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
index 3759909c..83f013a2 100644
--- a/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
+++ b/src/amdis/gridfunctions/DiscreteFunction.inc.hpp
@@ -10,14 +10,14 @@
 namespace AMDiS {
 
 // Evaluate DiscreteFunction in global coordinates
-template <class GB, class VT, class TP>
-typename DiscreteFunction<GB,VT,TP,true>::Range DiscreteFunction<GB,VT,TP,true>::
+template <class Coeff, class GB, class TP>
+typename DiscreteFunction<Coeff const,GB,TP>::Range DiscreteFunction<Coeff const,GB,TP>::
   operator()(Domain const& x) const
 {
   using Grid = typename GlobalBasis::GridView::Grid;
   using IS = typename GlobalBasis::GridView::IndexSet;
 
-  auto const& gv = this->basis()->gridView();
+  auto const& gv = this->basis().gridView();
   Dune::HierarchicSearch<Grid,IS> hsearch{gv.grid(), gv.indexSet()};
 
   auto element = hsearch.findEntity(x);
@@ -29,21 +29,21 @@ typename DiscreteFunction<GB,VT,TP,true>::Range DiscreteFunction<GB,VT,TP,true>:
 
 
 // Interpolation of GridFunction to DOFVector
-template <class GB, class VT, class TP>
+template <class Coeff, class GB, class TP>
   template <class Expr, class Tag>
-void DiscreteFunction<GB,VT,TP,false>::
+void DiscreteFunction<Coeff,GB,TP>::
   interpolate_noalias(Expr&& expr, Tag strategy)
 {
-  auto const& basis = *this->basis();
+  auto const& basis = this->basis();
   auto const& treePath = this->treePath();
 
   auto&& gf = makeGridFunction(FWD(expr), basis.gridView());
 
   if (std::is_same<Tag, tag::average>::value) {
-    auto counter = coefficients();
+    VectorType_t<short,Coeff> counter(basis);
     AMDiS::interpolate(basis, coefficients(), gf, treePath, counter);
 
-    coefficients().forEach([&counter](std::size_t dof, auto& coeff)
+    coefficients().forEach([&counter](auto dof, auto& coeff)
     {
       coeff /= std::max(double(counter.at(dof)), 1.0);
     });
@@ -54,19 +54,19 @@ void DiscreteFunction<GB,VT,TP,false>::
 
 
 // Interpolation of GridFunction to DOFVector
-template <class GB, class VT, class TP>
+template <class Coeff, class GB, class TP>
   template <class Expr, class Tag>
-void DiscreteFunction<GB,VT,TP,false>::
+void DiscreteFunction<Coeff,GB,TP>::
   interpolate(Expr&& expr, Tag strategy)
 {
   // create temporary copy of data
-  DOFVector<GB,VT> tmp(coefficients());
+  Coeff tmp(coefficients());
 
-  Self tmpView{tmp, this->treePath()};
+  Self tmpView{tmp, this->basis(), this->treePath()};
   tmpView.interpolate_noalias(FWD(expr), strategy);
 
   // move data from temporary vector into stored DOFVector
-  coefficients().backend() = std::move(tmp.backend());
+  coefficients() = std::move(tmp);
 }
 
 } // end namespace AMDiS
diff --git a/src/amdis/gridfunctions/DiscreteLocalFunction.inc.hpp b/src/amdis/gridfunctions/DiscreteLocalFunction.inc.hpp
index 899818c6..3380bb41 100644
--- a/src/amdis/gridfunctions/DiscreteLocalFunction.inc.hpp
+++ b/src/amdis/gridfunctions/DiscreteLocalFunction.inc.hpp
@@ -9,8 +9,8 @@
 
 namespace AMDiS {
 
-template <class GB, class VT, class TP>
-class DiscreteFunction<GB,VT,TP,true>::LocalFunction
+template <class Coeff, class GB, class TP>
+class DiscreteFunction<Coeff const,GB,TP>::LocalFunction
 {
 public:
   using Domain = typename EntitySet::LocalCoordinate;
@@ -27,14 +27,14 @@ public:
   /// Constructor. Stores a copy of the DiscreteFunction.
   LocalFunction(DiscreteFunction const& globalFunction)
     : globalFunction_(globalFunction)
-    , localView_(globalFunction_.basis()->localView())
+    , localView_(globalFunction_.basis().localView())
     , subTree_(&Dune::TypeTree::child(localView_.tree(), globalFunction_.treePath()))
   {}
 
   /// Copy constructor.
   LocalFunction(LocalFunction const& other)
     : globalFunction_(other.globalFunction_)
-    , localView_(globalFunction_.basis()->localView())
+    , localView_(globalFunction_.basis().localView())
     , subTree_(&Dune::TypeTree::child(localView_.tree(), globalFunction_.treePath()))
   {}
 
@@ -126,14 +126,14 @@ private:
   LocalView localView_;
   SubTree const* subTree_;
 
-  std::vector<VT> localCoefficients_;
+  std::vector<ValueType> localCoefficients_;
   bool bound_ = false;
 };
 
 
-template <class GB, class VT, class TP>
+template <class Coeff, class GB, class TP>
   template <class Type>
-class DiscreteFunction<GB,VT,TP,true>::DerivativeLocalFunctionBase
+class DiscreteFunction<Coeff const,GB,TP>::DerivativeLocalFunctionBase
 {
   using R = typename DiscreteFunction::Range;
   using D = typename DiscreteFunction::Domain;
@@ -156,7 +156,7 @@ public:
   DerivativeLocalFunctionBase(DiscreteFunction const& globalFunction, Type const& type)
     : globalFunction_(globalFunction)
     , type_(type)
-    , localView_(globalFunction_.basis()->localView())
+    , localView_(globalFunction_.basis().localView())
     , subTree_(&Dune::TypeTree::child(localView_.tree(), globalFunction_.treePath()))
   {}
 
@@ -164,7 +164,7 @@ public:
   DerivativeLocalFunctionBase(DerivativeLocalFunctionBase const& other)
     : globalFunction_(other.globalFunction_)
     , type_(other.type_)
-    , localView_(globalFunction_.basis()->localView())
+    , localView_(globalFunction_.basis().localView())
     , subTree_(&Dune::TypeTree::child(localView_.tree(), globalFunction_.treePath()))
   {}
 
@@ -214,13 +214,13 @@ protected:
   LocalView localView_;
   SubTree const* subTree_;
   Dune::Std::optional<Geometry> geometry_;
-  std::vector<VT> localCoefficients_;
+  std::vector<ValueType> localCoefficients_;
   bool bound_ = false;
 };
 
 
-template <class GB, class VT, class TP>
-class DiscreteFunction<GB,VT,TP,true>::GradientLocalFunction
+template <class Coeff, class GB, class TP>
+class DiscreteFunction<Coeff const,GB,TP>::GradientLocalFunction
     : public DerivativeLocalFunctionBase<tag::gradient>
 {
   using Super = DerivativeLocalFunctionBase<tag::gradient>;
@@ -271,8 +271,8 @@ public:
 };
 
 
-template <class GB, class VT, class TP>
-class DiscreteFunction<GB,VT,TP,true>::DivergenceLocalFunction
+template <class Coeff, class GB, class TP>
+class DiscreteFunction<Coeff const,GB,TP>::DivergenceLocalFunction
     : public DerivativeLocalFunctionBase<tag::divergence>
 {
   using Super = DerivativeLocalFunctionBase<tag::divergence>;
@@ -326,8 +326,8 @@ private:
 };
 
 
-template <class GB, class VT, class TP>
-class DiscreteFunction<GB,VT,TP,true>::PartialLocalFunction
+template <class Coeff, class GB, class TP>
+class DiscreteFunction<Coeff const,GB,TP>::PartialLocalFunction
     : public DerivativeLocalFunctionBase<tag::partial>
 {
   using Super = DerivativeLocalFunctionBase<tag::partial>;
diff --git a/src/amdis/io/FileWriterCreator.hpp b/src/amdis/io/FileWriterCreator.hpp
index 2c74bb15..77bf0154 100644
--- a/src/amdis/io/FileWriterCreator.hpp
+++ b/src/amdis/io/FileWriterCreator.hpp
@@ -3,6 +3,8 @@
 #include <memory>
 #include <string>
 
+#include <dune/common/typeutilities.hh>
+
 #include <amdis/BoundaryManager.hpp>
 #include <amdis/LinearAlgebra.hpp>
 #include <amdis/Output.hpp>
@@ -45,15 +47,15 @@ namespace AMDiS
     create(std::string type, std::string prefix, TreePath treePath = {}) const
     {
       auto data = makeDiscreteFunction(*systemVector_, treePath);
-      using Range = typename TYPEOF(data)::Range;
-
-      return create_impl(std::move(type), std::move(prefix), data, ValueCategory_t<Range>{});
+      return create_impl(std::move(type), std::move(prefix), data, Dune::PriorityTag<42>{});
     }
 
   private:
-    template <class Data, class ValCat>
+    template <class Data,
+      REQUIRES(not std::is_same<ValueCategory_t<typename Data::Range>,tag::unknown>::value),
+      REQUIRES(std::is_arithmetic<typename Dune::FieldTraits<typename Data::Range>::field_type>::value)>
     std::unique_ptr<FileWriterInterface>
-    create_impl(std::string type, std::string prefix, Data const& data, ValCat) const
+    create_impl(std::string type, std::string prefix, Data const& data, Dune::PriorityTag<2>) const
     {
       GridView const& gridView = systemVector_->basis()->gridView();
 
@@ -90,10 +92,13 @@ namespace AMDiS
       return {};
     }
 
+
     // The value-category is unknown, like a composite/hierarchic vector or any unknown type.
-    template <class Data>
+    template <class Data,
+      REQUIRES(std::is_same<ValueCategory_t<typename Data::Range>,tag::unknown>::value),
+      REQUIRES(std::is_arithmetic<typename Dune::FieldTraits<typename Data::Range>::field_type>::value)>
     std::unique_ptr<FileWriterInterface>
-    create_impl(std::string type, std::string prefix, Data const& /*data*/, tag::unknown) const
+    create_impl(std::string type, std::string prefix, Data const& /*data*/, Dune::PriorityTag<1>) const
     {
       // Backup writer, writing the grid and the solution vector
       if (type == "backup")
@@ -107,6 +112,15 @@ namespace AMDiS
       return {};
     }
 
+    // fallback implementation
+    template <class Data>
+    std::unique_ptr<FileWriterInterface>
+    create_impl(std::string, std::string, Data const&, Dune::PriorityTag<0>) const
+    {
+      error_exit("Filewriter cannot be used with unsupported Range and field_type");
+      return {};
+    }
+
   private:
     std::shared_ptr<SystemVector> systemVector_;
     std::shared_ptr<BoundaryManager<Grid>> boundaryManager_ = nullptr;
diff --git a/src/amdis/linearalgebra/CMakeLists.txt b/src/amdis/linearalgebra/CMakeLists.txt
index fb2d7db9..d89ab399 100644
--- a/src/amdis/linearalgebra/CMakeLists.txt
+++ b/src/amdis/linearalgebra/CMakeLists.txt
@@ -6,14 +6,16 @@ install(FILES
     DOFMapping.inc.hpp
     LinearSolver.hpp
     LinearSolverInterface.hpp
-    MatrixBase.hpp
+    MatrixFacade.hpp
     ParallelIndexSet.hpp
     PreconditionerInterface.hpp
     RunnerInterface.hpp
     SolverInfo.hpp
+    SparsityPattern.hpp
     SymmetryStructure.hpp
     Traits.hpp
-    VectorBase.hpp
+    VectorDefaultImplementation.hpp
+    VectorFacade.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/linearalgebra)
 
 if (BACKEND STREQUAL "MTL")
diff --git a/src/amdis/linearalgebra/Constraints.hpp b/src/amdis/linearalgebra/Constraints.hpp
index 03498fd1..b03dee88 100644
--- a/src/amdis/linearalgebra/Constraints.hpp
+++ b/src/amdis/linearalgebra/Constraints.hpp
@@ -5,7 +5,7 @@
 namespace AMDiS
 {
   // forward declaration
-  template <class RB, class CB, class T>
+  template <class RB, class CB, class T, class Traits>
   class BiLinearForm;
 
 
@@ -40,21 +40,21 @@ namespace AMDiS
   }
 
 
-  template <class RB, class CB, class T>
-  struct Constraints<BiLinearForm<RB,CB,T>>
+  template <class RB, class CB, class T, class Traits>
+  struct Constraints<BiLinearForm<RB,CB,T,Traits>>
   {
-    using Matrix = BiLinearForm<RB,CB,T>;
+    using Matrix = BiLinearForm<RB,CB,T,Traits>;
 
     template <class Sol, class Rhs, class BitVec>
     static void dirichletBC(Matrix& matrix, Sol& solution, Rhs& rhs, BitVec const& nodes, bool setDiagonal = true)
     {
-      AMDiS::dirichletBC(matrix.backend(), solution.backend(), rhs.backend(), nodes, setDiagonal);
+      AMDiS::dirichletBC(matrix.impl(), solution.impl(), rhs.impl(), nodes, setDiagonal);
     }
 
     template <class Sol, class Rhs, class BitVec, class Assoc>
     static void periodicBC(Matrix& matrix, Sol& solution, Rhs& rhs, BitVec const& left, Assoc const& association, bool setDiagonal = true)
     {
-      AMDiS::periodicBC(matrix.backend(), solution.backend(), rhs.backend(), left, association, setDiagonal);
+      AMDiS::periodicBC(matrix.impl(), solution.impl(), rhs.impl(), left, association, setDiagonal);
     }
   };
 
diff --git a/src/amdis/linearalgebra/DOFMapping.hpp b/src/amdis/linearalgebra/DOFMapping.hpp
index 38153fff..9192e4a5 100644
--- a/src/amdis/linearalgebra/DOFMapping.hpp
+++ b/src/amdis/linearalgebra/DOFMapping.hpp
@@ -16,6 +16,7 @@
 
 namespace AMDiS
 {
+  /// \brief Fallback for \ref ParallelDofMapping in case there is only one mpi core.
   template <class IS, class GI = std::size_t>
   class SequentialDofMapping
   {
@@ -152,6 +153,7 @@ namespace AMDiS
 
 
 #if HAVE_MPI
+  /// \brief Mapping of local to global indices
   template <class PIS, class GI = std::size_t>
   class ParallelDofMapping
   {
diff --git a/src/amdis/linearalgebra/MatrixBase.hpp b/src/amdis/linearalgebra/MatrixBase.hpp
deleted file mode 100644
index 38481bda..00000000
--- a/src/amdis/linearalgebra/MatrixBase.hpp
+++ /dev/null
@@ -1,133 +0,0 @@
-#pragma once
-
-#include <memory>
-#include <type_traits>
-
-#include <dune/common/shared_ptr.hh>
-
-#include <amdis/common/Concepts.hpp>
-#include <amdis/common/TypeTraits.hpp>
-#include <amdis/functions/NodeIndices.hpp>
-#include <amdis/linearalgebra/SymmetryStructure.hpp>
-#include <amdis/typetree/MultiIndex.hpp>
-
-namespace AMDiS
-{
-  /**
-   * Basis implementation of DOFMatrix, i.e. a sparse matrix storing all the
-   * assembled Operators indexed with DOF indices. The matrix data is associated
-   * to a row and column global basis.
-   *
-   * \tparam RB  Basis of the matrix rows
-   * \tparam CB  Basis of matrix columns
-   * \tparam B   A linear-algebra backend for the matrix storage
-   **/
-  template <class RB, class CB, class B>
-  class MatrixBase
-  {
-    using Self = MatrixBase;
-
-  public:
-    /// The type of the finite element space / basis of the row
-    using RowBasis = RB;
-    using RowLocalView = typename RowBasis::LocalView;
-
-    /// The type of the finite element space / basis of the column
-    using ColBasis = CB;
-    using ColLocalView = typename ColBasis::LocalView;
-
-    /// The Linear-Algebra backend used to store the assembled coefficients
-    using Backend = B;
-
-  public:
-    /// (1) Constructor. Stores the shared_ptr to the bases and the communication object.
-    MatrixBase(std::shared_ptr<RB> rowBasis, std::shared_ptr<CB> colBasis)
-      : rowBasis_(std::move(rowBasis))
-      , colBasis_(std::move(colBasis))
-      , backend_(*rowBasis_, *colBasis_)
-    {}
-
-    /// (2) Constructor. Forwards to (1) by wrapping reference into non-destroying
-    /// shared_ptr, see \ref Dune::wrap_or_move.
-    template <class RB_, class CB_,
-      REQUIRES(Concepts::Similar<Types<RB_,CB_>, Types<RB,CB>>)>
-    MatrixBase(RB_&& rowBasis, CB_&& colBasis)
-      : MatrixBase(Dune::wrap_or_move(FWD(rowBasis)), Dune::wrap_or_move(FWD(colBasis)))
-    {}
-
-    /// Return the row-basis \ref rowBasis of the matrix
-    std::shared_ptr<RowBasis> const& rowBasis() const
-    {
-      return rowBasis_;
-    }
-
-    /// Return the col-basis \ref colBasis of the matrix
-    std::shared_ptr<ColBasis> const& colBasis() const
-    {
-      return colBasis_;
-    }
-
-    /// Return the underlying linear algebra backend
-    Backend const& backend() const { return backend_; }
-    Backend&       backend()       { return backend_; }
-
-    /// \brief Initialize the matrix for insertion, i.e. allocate the non-zero pattern
-    /**
-     * With the optional parameter \p symmetry some additional information about the
-     * structure of the values or the sparsity pattern can be provided.
-     * See \ref SymmetryStructure.
-     **/
-    void init(SymmetryStructure symmetry = SymmetryStructure::unknown)
-    {
-      backend_.init(*rowBasis_, *colBasis_, symmetry);
-    }
-
-    /// Finish the matrix insertion, e.g. cleanup or final insertion
-    void finish()
-    {
-      backend_.finish();
-    }
-
-    /// Insert a single value into the matrix (add to existing value)
-    template <class RowIndex, class ColIndex>
-    void insert(RowIndex const& row, ColIndex const& col, typename Backend::value_type const& value)
-    {
-      backend_.insert(row, col, value);
-    }
-
-    /// Insert a block of values into the sparse matrix (add to existing values)
-    /// The global matrix indices are determined by the corresponding localviews.
-    template <class LocalMatrix>
-    void scatter(RowLocalView const& r, ColLocalView const& c, LocalMatrix const& localMatrix)
-    {
-      assert(r.size() * c.size() == localMatrix.size());
-      assert(r.size() == localMatrix.rows());
-      assert(c.size() == localMatrix.cols());
-
-      const bool optimized = std::is_same<RowLocalView,ColLocalView>::value
-        && r.tree().treeIndex() == c.tree().treeIndex();
-
-      if (optimized)
-        backend_.scatter(nodeIndices(r), localMatrix);
-      else
-        backend_.scatter(nodeIndices(r), nodeIndices(c), localMatrix);
-    }
-
-    /// Number of nonzeros in the matrix
-    std::size_t nnz() const
-    {
-      return backend_.nnz();
-    }
-
-  protected:
-    /// The finite element space / basis associated with the rows
-    std::shared_ptr<RowBasis> rowBasis_;
-
-    /// The finite element space / basis associated with the columns
-    std::shared_ptr<ColBasis> colBasis_;
-
-    /// Data backend
-    Backend backend_;
-  };
-
-} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/MatrixFacade.hpp b/src/amdis/linearalgebra/MatrixFacade.hpp
new file mode 100644
index 00000000..49adf77c
--- /dev/null
+++ b/src/amdis/linearalgebra/MatrixFacade.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <type_traits>
+
+#include <dune/common/shared_ptr.hh>
+#include <dune/functions/functionspacebases/concepts.hh>
+
+#include <amdis/common/Concepts.hpp>
+#include <amdis/common/TypeTraits.hpp>
+#include <amdis/functions/NodeIndices.hpp>
+#include <amdis/linearalgebra/SymmetryStructure.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
+
+namespace AMDiS
+{
+  /**
+   * Basis implementation of DOFMatrix, i.e. a sparse matrix storing all the
+   * assembled Operators indexed with DOF indices. The matrix data is associated
+   * to a row and column global basis.
+   *
+   * \tparam T          The coefficient type of the matrix
+   * \tparam Pattern    The type of the sparsity pattern
+   * \tparam MatrixImpl A linear-algebra backend for the matrix storage
+   **/
+  template <class T, class Pattern, template <class> class MatrixImpl>
+  class MatrixFacade
+  {
+    using Self = MatrixFacade;
+    using Impl = MatrixImpl<T>;
+
+    /// Type of the sparsity pattern of the backend
+    using SparsityPattern = Pattern;
+
+  public:
+    /// Constructor. Forwards the bases to the implementation class and 
+    /// constructs a matrix sparsity pattern.
+    template <class RowBasis, class ColBasis>
+    MatrixFacade(RowBasis const& rowBasis, ColBasis const& colBasis)
+      : impl_(rowBasis, colBasis)
+      , pattern_(rowBasis, colBasis)
+    {}
+
+    /// Return the underlying matrix backend
+    Impl const& impl() const { return impl_; }
+    Impl&       impl()       { return impl_; }
+
+    /// \brief Initialize the matrix for insertion, i.e. allocate the non-zero pattern
+    /**
+     * With the optional parameter \p symmetry some additional information about the
+     * structure of the values or the sparsity pattern can be provided.
+     * See \ref SymmetryStructure.
+     **/
+    void init(SymmetryStructure symmetry = SymmetryStructure::unknown)
+    {
+      impl_.init(pattern_, symmetry);
+    }
+
+    /// Finish the matrix insertion, e.g. cleanup or final insertion
+    void finish()
+    {
+      impl_.finish();
+    }
+
+    /// Insert a single value into the matrix (add to existing value)
+    template <class RowIndex, class ColIndex,
+      REQUIRES(Concepts::MultiIndex<RowIndex>),
+      REQUIRES(Concepts::MultiIndex<ColIndex>)>
+    void insert(RowIndex const& row, ColIndex const& col, typename Impl::value_type const& value)
+    {
+      impl_.insert(row, col, value);
+    }
+
+    /// Insert a block of values into the sparse matrix (add to existing values)
+    /// The global matrix indices are determined by the corresponding localviews.
+    template <class RowLocalView, class ColLocalView, class LocalMatrix,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename RowLocalView::GlobalBasis>, RowLocalView>()),
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename ColLocalView::GlobalBasis>, ColLocalView>())>
+    void scatter(RowLocalView const& r, ColLocalView const& c, LocalMatrix const& localMatrix)
+    {
+      assert(r.size() * c.size() == localMatrix.size());
+      assert(r.size() == localMatrix.rows());
+      assert(c.size() == localMatrix.cols());
+
+      const bool optimized = std::is_same<RowLocalView,ColLocalView>::value
+        && r.tree().treeIndex() == c.tree().treeIndex();
+
+      if (optimized)
+        impl_.scatter(nodeIndices(r), localMatrix);
+      else
+        impl_.scatter(nodeIndices(r), nodeIndices(c), localMatrix);
+    }
+
+    /// Number of nonzeros in the matrix
+    std::size_t nnz() const
+    {
+      return impl_.nnz();
+    }
+
+  protected:
+    /// The matrix backend
+    Impl impl_;
+
+    /// The structure of the non-zeros in the matrix
+    SparsityPattern pattern_;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/SparsityPattern.hpp b/src/amdis/linearalgebra/SparsityPattern.hpp
new file mode 100644
index 00000000..93efde60
--- /dev/null
+++ b/src/amdis/linearalgebra/SparsityPattern.hpp
@@ -0,0 +1,155 @@
+#pragma once
+
+#include <memory>
+
+#include <dune/istl/matrixindexset.hh>
+
+#include <amdis/Observer.hpp>
+#include <amdis/common/Index.hpp>
+
+namespace AMDiS
+{
+  /// \brief A general sparsity pattern implementation using the full pattern of the 
+  /// basis by adding all local indices
+  template <class RowBasis, class ColBasis>
+  class SparsityPattern
+      : private ObserverSequence<event::adapt,2>
+  {
+  public:
+    /// Constructor. Stores pointers to the passed bases.
+    SparsityPattern(RowBasis const& rowBasis, ColBasis const& colBasis)
+      : ObserverSequence<event::adapt,2>(rowBasis, colBasis)
+      , rowBasis_(&rowBasis)
+      , colBasis_(&colBasis)
+    {
+      updateImpl3();
+    }
+
+    /// Number of rows in the matrix
+    std::size_t rows() const
+    {
+      return rows_;
+    }
+
+    /// Number of columns in the matrix
+    std::size_t cols() const
+    {
+      return cols_;
+    }
+
+    /// Average number of non-zeros per row
+    std::size_t avgRowSize() const
+    {
+      assert(rows_ == pattern_.rows());
+      std::size_t sum = 0;
+      for (std::size_t r = 0; r < rows_; ++r)
+        sum += rowSize(r);
+      return (sum + rows_ - 1) / rows_;
+    }
+
+    /// Number of non-zeros in row r
+    std::size_t rowSize(std::size_t r) const
+    {
+      return pattern_.rowsize(r);
+    }
+
+    /// Total number of non-zeros
+    std::size_t nnz() const
+    {
+      return pattern_.size();
+    }
+
+    /// Initialize a matrix with the non-zero structure
+    template <class Matrix>
+    void applyTo(Matrix& matrix) const
+    {
+      pattern_.exportIdx(matrix);
+    }
+
+  protected:
+
+    void updateImpl(event::adapt e, index_t<0> i) override { updateImpl2(e,i); }
+    void updateImpl(event::adapt e, index_t<1> i) override { updateImpl2(e,i); }
+
+  private:
+
+    // Track for each basis wether updated and if both are, call updateImpl3()
+    template <std::size_t I>
+    void updateImpl2(event::adapt, index_t<I>)
+    {
+      assert(!updateCounter_.test(I));
+      updateCounter_.set(I);
+
+      if (updateCounter_.all()) {
+        updateImpl3();
+        updateCounter_.reset();
+      }
+    }
+
+    void updateImpl3()
+    {
+      rowBasis_ == colBasis_ 
+          ? updateSameBasis() 
+          : updateDifferentBasis();
+    }
+
+    // Update pattern when basis is updated. This method is called if rowBasis == colBasis.
+    void updateSameBasis()
+    {
+      rows_ = rowBasis_->dimension();
+      cols_ = rows_;
+      pattern_.resize(rows_, cols_);
+
+      auto localView = rowBasis_->localView();
+      for (const auto& element : elements(rowBasis_->gridView())) {
+        localView.bind(element);
+
+        for (std::size_t i = 0, size = localView.size(); i < size; ++i) {
+          // The global index of the i-th vertex of the element
+          auto row = localView.index(i);
+          for (std::size_t j = 0; j < size; ++j) {
+            // The global index of the j-th vertex of the element
+            auto col = localView.index(j);
+            pattern_.add(row, col);
+          }
+        }
+      }
+    }
+
+    // Update pattern when basis is updated. This method is called if rowBasis != colBasis.
+    void updateDifferentBasis()
+    {
+      rows_ = rowBasis_->dimension();
+      cols_ = colBasis_->dimension();
+      pattern_.resize(rows_, cols_);
+
+      auto rowLocalView = rowBasis_->localView();
+      auto colLocalView = colBasis_->localView();
+      for (const auto& element : elements(rowBasis_->gridView())) {
+        rowLocalView.bind(element);
+        colLocalView.bind(element);
+
+        for (std::size_t i = 0; i < rowLocalView.size(); ++i) {
+          // The global index of the i-th vertex of the element
+          auto row = rowLocalView.index(i);
+          for (std::size_t j = 0; j < colLocalView.size(); ++j) {
+            // The global index of the j-th vertex of the element
+            auto col = colLocalView.index(j);
+            pattern_.add(row, col);
+          }
+        }
+      }
+    }
+
+  private:
+    RowBasis const* rowBasis_;
+    ColBasis const* colBasis_;
+
+    std::bitset<2> updateCounter_ = 0;
+
+    std::size_t rows_;
+    std::size_t cols_;
+    Dune::MatrixIndexSet pattern_;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/VectorBase.hpp b/src/amdis/linearalgebra/VectorBase.hpp
index 25fc10ed..a0668a9a 100644
--- a/src/amdis/linearalgebra/VectorBase.hpp
+++ b/src/amdis/linearalgebra/VectorBase.hpp
@@ -1,445 +1,111 @@
 #pragma once
 
-#include <memory>
-#include <string>
-#include <type_traits>
-#include <utility>
+#include <iterator>
 
-#include <dune/common/classname.hh>
-#include <dune/common/deprecated.hh>
-#include <dune/common/hybridutilities.hh>
 #include <dune/common/rangeutilities.hh>
-#include <dune/common/shared_ptr.hh>
-#include <dune/common/std/type_traits.hh>
-#include <dune/functions/functionspacebases/concepts.hh>
-#include <dune/functions/functionspacebases/sizeinfo.hh>
+#include <dune/functions/functionspacebases/flatmultiindex.hh>
 
-#include <amdis/Output.hpp>
-#include <amdis/common/Concepts.hpp>
 #include <amdis/common/FakeContainer.hpp>
-#include <amdis/common/TypeTraits.hpp>
-#include <amdis/functions/NodeIndices.hpp>
-#include <amdis/operations/Assigner.hpp>
-#include <amdis/typetree/MultiIndex.hpp>
+#include <amdis/utility/MappedRangeView.hpp>
 
 namespace AMDiS
 {
-  /// \brief The basic container that stores a base vector and a corresponding basis
-  /**
-   * A vector storing all the assembled Operators indexed with DOF indices. The
-   * vector data is associated to a global basis.
-   *
-   * \tparam GB  Basis of the vector
-   * \tparam B   A linear algebra backend implementing the storage and operations.
-   **/
-  template <class GB, class B>
+  /// \brief CRTP base class for flat vector backends
+  template <class Derived>
   class VectorBase
   {
-    using Self = VectorBase;
-
-  public:
-    /// The type of the functionspace basis associated to this linearform
-    using GlobalBasis = GB;
-    using LocalView = typename GlobalBasis::LocalView;
-
-    /// The Linear-Algebra backend used to store the assembled coefficients
-    using Backend = B;
-
   private:
-    // proxy class redirecting the mutable element access to the insertValue method
-    template <class Index>
-    struct AccessProxy;
-
-    enum class VectorState
-    {
-      unknown = 0,
-      synchronized = 1,
-      insert_values = 2,
-      add_values = 3
-    };
-
-    template <class A>
-    using VectorStateOf_t = std::conditional_t<std::is_same<A,Assigner::plus_assign>::value,
-      std::integral_constant<VectorState, VectorState::add_values>,
-      std::integral_constant<VectorState, VectorState::insert_values>>;
-
-  public:
-    /// (1) Constructor. Stores the shared_ptr of the basis.
-    VectorBase(std::shared_ptr<GB> basis)
-      : basis_(std::move(basis))
-      , backend_(*basis_)
-    {
-      resizeZero();
-    }
-
-    /// (2) Constructor. Forwards to (1) by wrapping reference into non-destroying shared_ptr.
-    template <class GB_,
-      REQUIRES(Concepts::Similar<GB_,GB>)>
-    VectorBase(GB_&& basis)
-      : VectorBase(Dune::wrap_or_move(FWD(basis)))
-    {}
-
-    /// Return the basis \ref basis_ associated to the vector
-    std::shared_ptr<GlobalBasis> const& basis() const { return basis_; }
-    std::shared_ptr<GlobalBasis> const& basis()       { return basis_; }
-
-    /// Return the underlying linear algebra backend
-    Backend const& backend() const { return backend_; }
-    Backend&       backend()       { return backend_; }
-
-
-    template <class B_>
-    using HasLocalSize = decltype(std::declval<B_>().localSize());
-
-    template <class B_>
-    using HasGlobalSize = decltype(std::declval<B_>().globalSize());
-
-    /// Return the number of entries in the local part of the vector
-    std::size_t localSize() const
-    {
-      return Dune::Hybrid::ifElse(Dune::Std::is_detected<HasLocalSize,Backend>{},
-        [&](auto id) { return id(backend_).localSize(); },
-        [&](auto id) { return id(backend_).size(); });
-    }
-
-    /// Return the number of entries in the global vector
-    std::size_t globalSize() const
-    {
-      return Dune::Hybrid::ifElse(Dune::Std::is_detected<HasGlobalSize,Backend>{},
-        [&](auto id) { return id(backend_).globalSize(); },
-        [&](auto id) { return id(backend_).size(); });
-    }
-
-    /// Resize the \ref vector to the size of the \ref basis
-    void resize()
+    Derived const& asDerived() const
     {
-      backend_.init(sizeInfo(*basis_), false);
-      state_ = VectorState::unknown;
+      return static_cast<Derived const&>(*this);
     }
 
-    /// Resize the \ref vector to the size of the \ref basis and set to zero
-    void resizeZero()
+    Derived& asDerived()
     {
-      backend_.init(sizeInfo(*basis_), true);
-      state_ = VectorState::synchronized;
+      return static_cast<Derived&>(*this);
     }
 
-    /// Prepare the vector for insertion of values, finish the insertion with
-    /// \ref finish().
-    void init(bool clear)
-    {
-      backend_.init(sizeInfo(*basis_), clear);
-      state_ = clear ? VectorState::synchronized : VectorState::unknown;
-    }
-
-    /// Finish the insertion of values, see \ref init()
-    void finish()
-    {
-      backend_.finish();
-      state_ = VectorState::unknown;
-    }
-
-    /// Access the entry \p i of the \ref vector with read-only-access.
-    template <class Index>
-    typename Backend::value_type DUNE_DEPRECATED_MSG("Do not use element-wise vector access")
-    operator[](Index const& idx) const
-    {
-      assert(state_ == VectorState::synchronized || state_ == VectorState::unknown);
-      return at(idx);
-    }
-
-    /// Access the entry \p i of the \ref vector with write-access. Uses a proxy
-    /// class the redirects to \ref insertValue.
-    template <class Index>
-    AccessProxy<Index> DUNE_DEPRECATED_MSG("Do not use element-wise vector access")
-    operator[](Index const& idx)
-    {
-      return AccessProxy<Index>{this, idx};
-    }
-
-    /// Return the value of the vector at the local index \ref idx
-    template <class Index>
-    typename Backend::value_type at(Index const& idx) const
-    {
-      const_cast<Self*>(this)->synchronize();
-
-      return backend_.at(flatMultiIndex(idx));
-    }
-
-    /// \brief Insert a single value into the matrix (add or overwrite to existing value)
-    /**
-     * Inserts or adds a value into a certain location \p dof (given as dof multi-index)
-     * of a vector. The insertion mode is determined by the \p assign functor. Use
-     * \ref Assigner::plus_assign for adding values (default) or \ref Assigner::assign
-     * for overwriting (setting) values. Different insertion modes can not be mixed!
-     *
-     * Insertion must be closed with a call to \ref finish().
-     *
-     * [[not collective]]
-     */
-    template <class Index, class Assign = Assigner::plus_assign>
-    void insert(Index const& dof, typename Backend::value_type const& value, Assign assign = {})
-    {
-      test_exit_dbg(state_ == VectorStateOf_t<Assign>::value ||
-                    state_ == VectorState::unknown ||
-                    state_ == VectorState::synchronized,
-        "Vector in invalid state {} for insertion by {}.", to_string(state_), Dune::className<Assign>());
-
-      backend_.insert(flatMultiIndex(dof), value, assign);
+  protected:
+    /// Protected constructor prevents from direct construction of this class.
+    /// Only use it as base class in the sense of CRTP.
+    VectorBase() = default;
 
-      // set the state to insert_values or add_values
-      state_ = VectorStateOf_t<Assign>::value;
-    }
-
-    /// See \ref insert for assignment operation \ref Assigner::assign
-    template <class Index>
-    void set(Index const& dof, typename Backend::value_type const& value)
-    {
-      insert(dof, value, Assigner::assign{});
-    }
+  public:
+    void finish() { /* do nothing */ }
+    void synchronize() { /* do nothing */ }
 
-    /// See \ref insert for assignment operation \ref Assigner::plus_assign
-    template <class Index>
-    void add(Index const& dof, typename Backend::value_type const& value)
+    /// Insert or add \p value at position \p idx, using the passed \p assign functor.
+    template <class MultiIndex, class ValueType, class Assign>
+    void insert(MultiIndex const& idx, ValueType const& value, Assign assign)
     {
-      insert(dof, value, Assigner::plus_assign{});
+      assign(value, asDerived().at(idx));
     }
 
-
-    /// \brief Extract values from the vector referring to the given local indices
-    /// and store it into a buffer
-    /**
-     * Collect value of indices and store them into a buffer. The buffer must be
-     * a vector-like container with `buffer.resize()` and `buffer.begin()`. The
-     * indices must be stored in an iterable container.
-     *
-     * If the vector is not in synchronized state, collects all necessary values
-     * possibly from neighbouring processors.
-     *
-     * [[expects: localView is bound to an element]]
-     * [[expects: node is in localView.tree()]]
-     * [[possibly neighbor-wise collective operation]]
-     */
-    template <class Node, class Buffer,
-      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
-    void gather(LocalView const& localView, Node const& node, Buffer& buffer) const
+    /// Gather values from the vector into the output range \p buffer decribed as an output iterator
+    template <class IndexRange, class OutputIterator>
+    void gather(IndexRange const& localInd, OutputIterator buffer) const
     {
-      test_exit(state_ == VectorState::unknown ||
-                state_ == VectorState::synchronized,
-        "Vector in invalid state {} for gather operations.", to_string(state_));
-
-      const_cast<Self*>(this)->synchronize();
-
-      buffer.resize(node.size());
-      backend_.gather(nodeIndices(localView, node), buffer.begin());
+      for (auto const& idx : localInd)
+        *buffer++ = asDerived().at(idx);
     }
 
-    // [[expects: localView is bound to an element]]
-    template <class Buffer>
-    void gather(LocalView const& localView, Buffer& buffer) const
-    {
-      gather(localView, localView.tree(), buffer);
-    }
 
-    /// Insert a block of values into the vector (add or overwrite to existing values)
-    /**
-     * Inserts or adds values into certain locations of a vector. Insertion indices
-     * are extracted from the given \p localView. The insertion mode is determined
-     * by the \p assign functor. Use \ref Assigner::plus_assign for adding values
-     * (default) or \ref Assigner::assign for overwriting (setting) values. Different
-     * insertion modes can not be mixed! The \p localVector is assumed to be a continuous
-     * memory container with a `data()` method to get a pointer to the beginning.
-     *
-     * The \p mask models a boolean range with at least a `begin()` method. Must
-     * be forward iterable for at least `localVector.size()` elements. Does not
-     * need an `end()` method. See, e.g. \ref FakeContainer.
-     *
-     * Insertion must be closed with a call to \ref finish(). It is not allowed
-     * to switch insertion mode before calling `finish()`.
-     *
-     * [[expects: localView is bound to an element]]
-     * [[expects: node is in localView.tree()]]
-     * [[not collective]]
-     */
-    template <class Node, class NodeVector, class MaskRange, class Assign,
-      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
-    void scatter(LocalView const& localView, Node const& node, NodeVector const& localVector,
-                 MaskRange const& mask, Assign assign)
+    /// Scatter the values from the local \p vec into the container using the passed \p assign functor.
+    template <class IndexRange, class LocalVec, class Assign>
+    void scatter(IndexRange const& localInd, LocalVec const& vec, FakeContainer<bool,true>, Assign assign)
     {
-      test_exit(state_ == VectorStateOf_t<Assign>::value ||
-                state_ == VectorState::unknown ||
-                state_ == VectorState::synchronized,
-        "Vector in invalid state {} for insertion by {}.", to_string(state_), Dune::className<Assign>());
-
-      assert(localVector.size() == node.size());
-
-      // create a range of DOF indices on the node
-      backend_.scatter(nodeIndices(localView, node), localVector, mask, assign);
-
-      // set the state to insert_values or add_values
-      state_ = VectorStateOf_t<Assign>::value;
+      auto vec_it = std::begin(vec);
+      for (auto const& idx : localInd)
+        assign(*vec_it++, asDerived().at(idx));
     }
 
-    /// Call \ref scatter with `MaskRange` set to \ref FakeContainer.
-    // [[expects: localView is bound to an element]]
-    // [[expects: node is in localView.tree()]]
-    template <class Node, class NodeVector, class Assign,
-      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
-    void scatter(LocalView const& localView, Node const& node, NodeVector const& localVector, Assign assign)
+    /// Scatter some values from the local \p vec into the container using the passed \p assign functor.
+    /// The values to scatter are selected using the \p mask range that needs to be forward iterable.
+    template <class IndexRange, class LocalVec, class MaskRange, class Assign>
+    void scatter(IndexRange const& localInd, LocalVec const& vec, MaskRange const& mask, Assign assign)
     {
-      scatter(localView, node, localVector, FakeContainer<bool,true>{}, assign);
+      auto vec_it = std::begin(vec);
+      auto mask_it = std::begin(mask);
+      auto ind_it = std::begin(localInd);
+      for (; vec_it != std::end(vec); ++vec_it, ++mask_it, ++ind_it) {
+        if (*mask_it)
+          assign(*vec_it, asDerived().at(*ind_it));
+      }
     }
 
-    /// Call \ref scatter with `Node` given by the tree of the \p localView.
-    // [[expects: localView is bound to an element]]
-    template <class LocalVector, class Assign>
-    void scatter(LocalView const& localView, LocalVector const& localVector, Assign assign)
-    {
-      scatter(localView, localView.tree(), localVector, assign);
-    }
 
-    /// Copies a block of values from \p vector to this
-    /**
-     * The values to copy might be masked with the range \p mask.
-     * The assignment mode \p assign must be one of \ref Assigner::assign, or
-     * \ref Assigner::plus_Assign.
-     *
-     * Requires the (local) size of the vector to be equal to the basis dimension.
-     *
-     * [[not collective]]
-     **/
-    template <class Vector, class MaskRange, class Assign>
-    void copy(Vector const& vector, MaskRange const& mask, Assign assign)
+    /// Apply the functor \p f to all entries of the list of multi-indices \p localInd.
+    template <class IndexRange, class Func>
+    void forEach(IndexRange const& localInd, Func&& f) const
     {
-      test_exit(state_ == VectorStateOf_t<Assign>::value ||
-                state_ == VectorState::unknown ||
-                state_ == VectorState::synchronized,
-        "Vector in invalid state {} for insertion by {}.", to_string(state_), Dune::className<Assign>());
-
-      using size_type = typename Backend::size_type;
-      size_type size = sizeInfo(*basis_);
-      backend_.scatter(Dune::range(size), vector, mask, assign);
-
-      // set the state to insert_values or add_values
-      state_ = VectorStateOf_t<Assign>::value;
+      for (auto const& idx : localInd)
+        f(idx, asDerived().at(idx));
     }
 
-    /// Call \ref copy with `MaskRange` set to \ref FakeContainer.
-    template <class Vector, class Assign>
-    void copy(Vector const& vector, Assign assign)
+    /// Apply the functor \p f to all entries of the list of multi-indices \p localInd.
+    template <class IndexRange, class Func>
+    void forEach(IndexRange const& localInd, Func&& f)
     {
-      copy(vector, FakeContainer<bool,true>{}, assign);
+      for (auto const& idx : localInd)
+        f(idx, asDerived().at(idx));
     }
 
-    /// Apply \p func to each value at given indices \p localInd
-    /**
-     * First, synchronizes the values of the vector, then applies the functor to
-     * each local value associated to the local indices \p localInd.
-     *
-     * [[mutable]]
-     **/
-    template <class LocalInd, class Func>
-    void forEach(LocalInd const& localInd, Func&& func)
-    {
-      synchronize();
-      backend_.forEach(localInd, FWD(func));
-    }
 
-    /// Call \ref forEach for all entries in the vector.
+    /// Apply the functor \p f to all entries of the container
     template <class Func>
-    void forEach(Func&& func)
-    {
-      using size_type = typename Backend::size_type;
-      size_type size = sizeInfo(*basis_);
-      forEach(Dune::range(size), FWD(func));
-    }
-
-    /// Apply \p func to each value at given indices \p localInd
-    /**
-     * First, synchronizes the values of the vector, then applies the functor to
-     * each local value associated to the local indices \p localInd.
-     *
-     * [[const]]
-     **/
-    template <class LocalInd, class Func>
-    void forEach(LocalInd const& localInd, Func&& func) const
+    void forEach(Func&& f) 
     {
-      const_cast<Self*>(this)->synchronize();
-      backend_.forEach(localInd, FWD(func));
+      forEach(mappedRangeView(Dune::range(asDerived().size()),
+        [](auto i) { return Dune::Functions::FlatMultiIndex<decltype(i)>{i}; }), FWD(f));
     }
 
-    /// Call \ref forEach for all entries in the vector.
+    /// Apply the functor \p f to all entries of the container
     template <class Func>
-    void forEach(Func&& func) const
-    {
-      using size_type = typename Backend::size_type;
-      size_type size = sizeInfo(*basis_);
-      forEach(Dune::range(size), FWD(func));
-    }
-
-
-  private:
-    // synchronizes ghost values. Does not touch owned values
-    void synchronize()
-    {
-      if (state_ != VectorState::synchronized)
-        backend_.synchronize();
-
-      state_ = VectorState::synchronized;
-    }
-
-    // print the vector state to string for debugging purposes
-    static std::string to_string(VectorState state)
-    {
-      switch (state) {
-        case VectorState::synchronized: return "synchronized";
-        case VectorState::insert_values: return "insert_values";
-        case VectorState::add_values: return "add_values";
-        default: return "unknown";
-      }
-    }
-
-  private:
-    /// The finite element space / basis associated with the data vector
-    std::shared_ptr<GlobalBasis> basis_;
-
-    /// Data backend
-    Backend backend_;
-
-    /// The current state of the vector, one of {synchronized, insert_values,
-    /// add_values, unknown}
-    VectorState state_ = VectorState::unknown;
-  };
-
-
-  template <class GB, class B>
-    template <class Index>
-  struct VectorBase<GB,B>::AccessProxy
-  {
-    using value_type = typename Backend::value_type;
-
-    void operator=(value_type const& value)
-    {
-      self->set(i, value);
-    }
-
-    void operator+=(value_type const& value)
-    {
-      self->add(i, value);
-    }
-
-    void operator-=(value_type const& value)
-    {
-      self->add(i, -value);
-    }
-
-    operator value_type() const
+    void forEach(Func&& f) const 
     {
-      return self->at(i);
+      forEach(mappedRangeView(Dune::range(asDerived().size()),
+        [](auto i) { return Dune::Functions::FlatMultiIndex<decltype(i)>{i}; }), FWD(f));
     }
-
-    VectorBase* self;
-    Index i;
   };
 
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/VectorFacade.hpp b/src/amdis/linearalgebra/VectorFacade.hpp
new file mode 100644
index 00000000..a60d20e5
--- /dev/null
+++ b/src/amdis/linearalgebra/VectorFacade.hpp
@@ -0,0 +1,370 @@
+#pragma once
+
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include <dune/common/classname.hh>
+#include <dune/common/deprecated.hh>
+#include <dune/common/hybridutilities.hh>
+#include <dune/common/rangeutilities.hh>
+#include <dune/common/shared_ptr.hh>
+#include <dune/common/std/type_traits.hh>
+#include <dune/functions/functionspacebases/concepts.hh>
+#include <dune/functions/functionspacebases/sizeinfo.hh>
+
+#include <amdis/Output.hpp>
+#include <amdis/common/Concepts.hpp>
+#include <amdis/common/FakeContainer.hpp>
+#include <amdis/common/TypeTraits.hpp>
+#include <amdis/functions/NodeIndices.hpp>
+#include <amdis/functions/SizeInfo.hpp>
+#include <amdis/operations/Assigner.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
+
+namespace AMDiS
+{
+  /// \brief The basic container that stores a base vector and a corresponding basis
+  /**
+   * A vector storing all the assembled Operators indexed with DOF indices. The
+   * vector data is associated to a global basis.
+   *
+   * \tparam T            The coefficient type of the vector
+   * \tparam VectorImpl   A linear-algebra backend for the vector storage
+   **/
+  template <class T, template <class> class VectorImpl>
+  class VectorFacade
+  {
+    using Self = VectorFacade;
+    using Impl = VectorImpl<T>;
+
+  private:
+    // States the vector can be in. Is changed on various insertion or gathering methods.
+    enum class VectorState
+    {
+      unknown = 0,
+      synchronized = 1,
+      insert_values = 2,
+      add_values = 3
+    };
+
+    template <class A>
+    using VectorStateOf_t = std::conditional_t<std::is_same<A,Assigner::plus_assign>::value,
+      std::integral_constant<VectorState, VectorState::add_values>,
+      std::integral_constant<VectorState, VectorState::insert_values>>;
+
+  public:
+    using size_type = typename Impl::size_type;
+    using value_type = typename Impl::value_type;
+
+    /// Constructor. Forwards the basis to the implementation class and 
+    /// constructs a (type-erased) size-info object.
+    template <class GlobalBasis,
+      class = void_t<decltype(std::declval<GlobalBasis>().dimension())> >
+    VectorFacade(GlobalBasis const& basis)
+      : impl_(basis)
+      , sizeInfo_(sizeInfo(basis))
+    {
+      resizeZero();
+    }
+
+    /// Return the underlying linear algebra backend
+    Impl const& impl() const { return impl_; }
+    Impl&       impl()       { return impl_; }
+
+
+    template <class V>
+    using HasLocalSize = decltype(std::declval<V>().localSize());
+
+    template <class V>
+    using HasGlobalSize = decltype(std::declval<V>().globalSize());
+
+    /// Return the number of entries in the local part of the vector
+    std::size_t localSize() const
+    {
+      return Dune::Hybrid::ifElse(Dune::Std::is_detected<HasLocalSize,Impl>{},
+        [&](auto id) { return id(impl_).localSize(); },
+        [&](auto id) { return id(impl_).size(); });
+    }
+
+    /// Return the number of entries in the global vector
+    std::size_t globalSize() const
+    {
+      return Dune::Hybrid::ifElse(Dune::Std::is_detected<HasGlobalSize,Impl>{},
+        [&](auto id) { return id(impl_).globalSize(); },
+        [&](auto id) { return id(impl_).size(); });
+    }
+
+    /// Resize the \ref vector to the size of the \ref basis
+    void resize()
+    {
+      init(false);
+    }
+
+    /// Resize the \ref vector to the size of the \ref basis and set to zero
+    void resizeZero()
+    {
+      init(true);
+    }
+
+    /// Prepare the vector for insertion of values, finish the insertion with
+    /// \ref finish().
+    void init(bool clear)
+    {
+      impl_.init(sizeInfo_, clear);
+      state_ = clear ? VectorState::synchronized : VectorState::unknown;
+    }
+
+    /// Finish the insertion of values, see \ref init()
+    void finish()
+    {
+      impl_.finish();
+      state_ = VectorState::unknown;
+    }
+
+    /// Return the value of the vector at the local index \ref idx
+    template <class Index,
+      REQUIRES(Concepts::MultiIndex<Index>)>
+    typename Impl::value_type at(Index const& idx) const
+    {
+      const_cast<Self*>(this)->synchronize();
+      return impl_.at(idx);
+    }
+
+    /// \brief Insert a single value into the matrix (add or overwrite to existing value)
+    /**
+     * Inserts or adds a value into a certain location \p dof (given as dof multi-index)
+     * of a vector. The insertion mode is determined by the \p assign functor. Use
+     * \ref Assigner::plus_assign for adding values (default) or \ref Assigner::assign
+     * for overwriting (setting) values. Different insertion modes can not be mixed!
+     *
+     * Insertion must be closed with a call to \ref finish().
+     *
+     * [[not collective]]
+     */
+    template <class Index, class Assign = Assigner::plus_assign,
+      REQUIRES(Concepts::MultiIndex<Index>)>
+    void insert(Index const& idx, typename Impl::value_type const& value, Assign assign = {})
+    {
+      test_exit_dbg(state_ == VectorStateOf_t<Assign>::value ||
+                    state_ == VectorState::unknown ||
+                    state_ == VectorState::synchronized,
+        "Vector in invalid state {} for insertion by {}.", to_string(state_), Dune::className<Assign>());
+
+      impl_.insert(idx, value, assign);
+
+      // set the state to insert_values or add_values
+      state_ = VectorStateOf_t<Assign>::value;
+    }
+
+    /// See \ref insert for assignment operation \ref Assigner::assign
+    template <class Index,
+      REQUIRES(Concepts::MultiIndex<Index>)>
+    void set(Index const& idx, typename Impl::value_type const& value)
+    {
+      insert(idx, value, Assigner::assign{});
+    }
+
+    /// See \ref insert for assignment operation \ref Assigner::plus_assign
+    template <class Index,
+      REQUIRES(Concepts::MultiIndex<Index>)>
+    void add(Index const& idx, typename Impl::value_type const& value)
+    {
+      insert(idx, value, Assigner::plus_assign{});
+    }
+
+
+    /// \brief Extract values from the vector referring to the given local indices
+    /// and store it into a buffer
+    /**
+     * Collect value of indices and store them into a buffer. The buffer must be
+     * a vector-like container with `buffer.resize()` and `buffer.begin()`. The
+     * indices must be stored in an iterable container.
+     *
+     * If the vector is not in synchronized state, collects all necessary values
+     * possibly from neighbouring processors.
+     *
+     * [[expects: localView is bound to an element]]
+     * [[expects: node is in localView.tree()]]
+     * [[possibly neighbor-wise collective operation]]
+     */
+    template <class LocalView, class Node, class Buffer,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>()),
+      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
+    void gather(LocalView const& localView, Node const& node, Buffer& buffer) const
+    {
+      test_exit(state_ == VectorState::unknown ||
+                state_ == VectorState::synchronized,
+        "Vector in invalid state {} for gather operations.", to_string(state_));
+
+      const_cast<Self*>(this)->synchronize();
+
+      buffer.resize(node.size());
+      impl_.gather(nodeIndices(localView, node), buffer.begin());
+    }
+
+    // [[expects: localView is bound to an element]]
+    template <class LocalView, class Buffer,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>())>
+    void gather(LocalView const& localView, Buffer& buffer) const
+    {
+      gather(localView, localView.tree(), buffer);
+    }
+
+    /// Insert a block of values into the vector (add or overwrite to existing values)
+    /**
+     * Inserts or adds values into certain locations of a vector. Insertion indices
+     * are extracted from the given \p localView. The insertion mode is determined
+     * by the \p assign functor. Use \ref Assigner::plus_assign for adding values
+     * (default) or \ref Assigner::assign for overwriting (setting) values. Different
+     * insertion modes can not be mixed! The \p localVector is assumed to be a continuous
+     * memory container with a `data()` method to get a pointer to the beginning.
+     *
+     * The \p mask models a boolean range with at least a `begin()` method. Must
+     * be forward iterable for at least `localVector.size()` elements. Does not
+     * need an `end()` method. See, e.g. \ref FakeContainer.
+     *
+     * Insertion must be closed with a call to \ref finish(). It is not allowed
+     * to switch insertion mode before calling `finish()`.
+     *
+     * [[expects: localView is bound to an element]]
+     * [[expects: node is in localView.tree()]]
+     * [[not collective]]
+     */
+    template <class LocalView, class Node, class NodeVector, class MaskRange, class Assign,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>()),
+      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
+    void scatter(LocalView const& localView, Node const& node, NodeVector const& localVector,
+                 MaskRange const& mask, Assign assign)
+    {
+      test_exit(state_ == VectorStateOf_t<Assign>::value ||
+                state_ == VectorState::unknown ||
+                state_ == VectorState::synchronized,
+        "Vector in invalid state {} for insertion by {}.", to_string(state_), Dune::className<Assign>());
+
+      assert(localVector.size() == node.size());
+
+      // create a range of DOF indices on the node
+      impl_.scatter(nodeIndices(localView, node), localVector, mask, assign);
+
+      // set the state to insert_values or add_values
+      state_ = VectorStateOf_t<Assign>::value;
+    }
+
+    /// Call \ref scatter with `MaskRange` set to \ref FakeContainer.
+    // [[expects: localView is bound to an element]]
+    // [[expects: node is in localView.tree()]]
+    template <class LocalView, class Node, class NodeVector, class Assign,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>()),
+      REQUIRES(Dune::models<Dune::Functions::Concept::BasisNode, Node>())>
+    void scatter(LocalView const& localView, Node const& node, NodeVector const& localVector, Assign assign)
+    {
+      scatter(localView, node, localVector, FakeContainer<bool,true>{}, assign);
+    }
+
+    /// Call \ref scatter with `Node` given by the tree of the \p localView.
+    // [[expects: localView is bound to an element]]
+    template <class LocalView, class LocalVector, class Assign,
+      REQUIRES(Dune::models<Dune::Functions::Concept::LocalView<typename LocalView::GlobalBasis>, LocalView>())>
+    void scatter(LocalView const& localView, LocalVector const& localVector, Assign assign)
+    {
+      scatter(localView, localView.tree(), localVector, assign);
+    }
+
+    /// Apply \p func to each value at given indices \p localInd
+    /**
+     * First, synchronizes the values of the vector, then applies the functor to
+     * each local value associated to the local indices \p localInd.
+     *
+     * [[mutable]]
+     **/
+    template <class LocalInd, class Func>
+    void forEach(LocalInd const& localInd, Func&& func)
+    {
+      synchronize();
+      impl_.forEach(localInd, FWD(func));
+    }
+
+    /// Call \ref forEach for all entries in the vector.
+    template <class Func>
+    void forEach(Func&& func)
+    {
+      synchronize();
+      impl_.forEach(FWD(func));
+    }
+
+    /// Apply \p func to each value at given indices \p localInd
+    /**
+     * First, synchronizes the values of the vector, then applies the functor to
+     * each local value associated to the local indices \p localInd.
+     *
+     * [[const]]
+     **/
+    template <class LocalInd, class Func>
+    void forEach(LocalInd const& localInd, Func&& func) const
+    {
+      const_cast<Self*>(this)->synchronize();
+      impl_.forEach(localInd, FWD(func));
+    }
+
+    /// Call \ref forEach for all entries in the vector.
+    template <class Func>
+    void forEach(Func&& func) const
+    {
+      const_cast<Self*>(this)->synchronize();
+      impl_.forEach(FWD(func));
+    }
+
+
+  private:
+    // synchronizes ghost values. Does not touch owned values
+    void synchronize()
+    {
+      if (state_ != VectorState::synchronized)
+        impl_.synchronize();
+
+      state_ = VectorState::synchronized;
+    }
+
+    // print the vector state to string for debugging purposes
+    static std::string to_string(VectorState state)
+    {
+      switch (state) {
+        case VectorState::synchronized: return "synchronized";
+        case VectorState::insert_values: return "insert_values";
+        case VectorState::add_values: return "add_values";
+        default: return "unknown";
+      }
+    }
+
+  private:
+    /// Data backend
+    Impl impl_;
+
+    /// Functor returning the basis dimension
+    SizeInfo sizeInfo_;
+
+    /// The current state of the vector, one of {synchronized, insert_values,
+    /// add_values, unknown}
+    VectorState state_ = VectorState::unknown;
+  };
+
+
+  namespace Impl
+  {
+    template <class T, class Facade>
+    struct VectorTypeImpl;
+
+    template <class T, class S, template <class> class Impl>
+    struct VectorTypeImpl<T,VectorFacade<S,Impl>>
+    {
+      using type = VectorFacade<T,Impl>;
+    };
+
+  } // end namespace Impl
+
+  /// Type transformation changing the value type of the vector
+  template <class T, class Facade>
+  using VectorType_t = typename Impl::VectorTypeImpl<T,Facade>::type;
+
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/eigen/CMakeLists.txt b/src/amdis/linearalgebra/eigen/CMakeLists.txt
index a7c200cb..908d643b 100644
--- a/src/amdis/linearalgebra/eigen/CMakeLists.txt
+++ b/src/amdis/linearalgebra/eigen/CMakeLists.txt
@@ -3,6 +3,7 @@ install(FILES
     DirectRunner.hpp
     IterativeRunner.hpp
     MatrixBackend.hpp
+    MatrixSize.hpp
     PreconConfig.hpp
     SolverConfig.hpp
     SolverCreator.hpp
diff --git a/src/amdis/linearalgebra/eigen/Constraints.hpp b/src/amdis/linearalgebra/eigen/Constraints.hpp
index f5a6842e..24f7e227 100644
--- a/src/amdis/linearalgebra/eigen/Constraints.hpp
+++ b/src/amdis/linearalgebra/eigen/Constraints.hpp
@@ -11,11 +11,11 @@
 
 namespace AMDiS
 {
-  template <class Traits>
-  struct Constraints<MatrixBackend<Traits>>
+  template <class T, int O>
+  struct Constraints<EigenSparseMatrix<T,O>>
   {
-    using Matrix = MatrixBackend<Traits>;
-    using Vector = VectorBackend<Traits>;
+    using Matrix = EigenSparseMatrix<T,O>;
+    using Vector = EigenVector<T>;
 
     template <class BitVector>
     static void dirichletBC(Matrix& mat, Vector& sol, Vector& rhs, BitVector const& nodes, bool setDiagonal = true)
@@ -37,7 +37,7 @@ namespace AMDiS
     }
 
   protected:
-    template <class T, class BitVector>
+    template <class BitVector>
     static void clearDirichletRow(Eigen::SparseMatrix<T, Eigen::ColMajor>& mat, BitVector const& nodes, bool setDiagonal)
     {
       using Mat = Eigen::SparseMatrix<T, Eigen::ColMajor>;
@@ -51,7 +51,7 @@ namespace AMDiS
       }
     }
 
-    template <class T, class BitVector>
+    template <class BitVector>
     static void clearDirichletRow(Eigen::SparseMatrix<T, Eigen::RowMajor>& mat, BitVector const& nodes, bool setDiagonal)
     {
       using Mat = Eigen::SparseMatrix<T, Eigen::RowMajor>;
diff --git a/src/amdis/linearalgebra/eigen/MatrixBackend.hpp b/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
index ed184958..b4e45262 100644
--- a/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/eigen/MatrixBackend.hpp
@@ -5,6 +5,8 @@
 #include <string>
 #include <vector>
 
+#include <Eigen/SparseCore>
+
 #include <dune/common/timer.hh>
 
 #include <amdis/Output.hpp>
@@ -14,14 +16,12 @@ namespace AMDiS
 {
   /// \brief The basic container that stores a base matrix and a corresponding
   /// row/column feSpace.
-  template <class T>
-  class MatrixBackend
+  template <class T, int Orientation = Eigen::RowMajor>
+  class EigenSparseMatrix
   {
   public:
-    using Traits = T;
-
     /// The matrix type of the underlying base matrix
-    using BaseMatrix = typename Traits::Mat;
+    using BaseMatrix = Eigen::SparseMatrix<T, Orientation>;
 
     /// The type of the elements of the DOFMatrix
     using value_type = typename BaseMatrix::Scalar;
@@ -32,7 +32,7 @@ namespace AMDiS
   public:
     /// Constructor. Constructs new BaseMatrix.
     template <class Basis>
-    explicit MatrixBackend(Basis const&, Basis const&) {}
+    explicit EigenSparseMatrix(Basis const&, Basis const&) {}
 
     /// Return a reference to the data-matrix \ref matrix
     BaseMatrix& matrix()
@@ -74,10 +74,10 @@ namespace AMDiS
 
 
     /// Create inserter. Assumes that no inserter is currently active on this matrix.
-    template <class RowBasis, class ColBasis>
-    void init(RowBasis const& rowBasis, ColBasis const& colBasis, SymmetryStructure symmetry)
+    template <class Pattern>
+    void init(Pattern const& pattern, SymmetryStructure symmetry)
     {
-      matrix_.resize(rowBasis.dimension(), colBasis.dimension());
+      matrix_.resize(pattern.rows(), pattern.cols());
       matrix_.setZero();
     }
 
diff --git a/src/amdis/linearalgebra/eigen/MatrixSize.hpp b/src/amdis/linearalgebra/eigen/MatrixSize.hpp
new file mode 100644
index 00000000..18364e93
--- /dev/null
+++ b/src/amdis/linearalgebra/eigen/MatrixSize.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <functional>
+#include <memory>
+
+#include <amdis/Observer.hpp>
+#include <amdis/common/Index.hpp>
+
+namespace AMDiS
+{
+  class MatrixSize
+      : private ObserverSequence<event::adapt,2>
+  {
+    struct BasisCallback
+    {
+      template <class Basis>
+      explicit BasisCallback(Basis const* basis)
+        : dimension([basis](){ return basis->dimension(); })
+      {}
+
+      std::function<std::size_t()> dimension;
+    };
+
+  public:
+    template <class RowBasis, class ColBasis>
+    MatrixSize(RowBasis const& rowBasis, ColBasis const& colBasis)
+      : ObserverSequence<event::adapt,2>(rowBasis, colBasis)
+      , rowBasis_(&rowBasis)
+      , colBasis_(&colBasis)
+    {
+      updateImpl(event::adapt{true}, index_t<0>{});
+      updateImpl(event::adapt{true}, index_t<1>{});
+    }
+
+    /// Number of rows in the matrix
+    std::size_t rows() const
+    {
+      return rows_;
+    }
+
+    /// Number of columns in the matrix
+    std::size_t cols() const
+    {
+      return cols_;
+    }
+
+  protected:
+
+    void updateImpl(event::adapt e, index_t<0> i) final { rows_ = rowBasis_.dimension(); }
+    void updateImpl(event::adapt e, index_t<1> i) final { cols_ = colBasis_.dimension(); }
+
+  private:
+    BasisCallback rowBasis_;
+    BasisCallback colBasis_;
+
+    std::size_t rows_;
+    std::size_t cols_;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/eigen/Traits.hpp b/src/amdis/linearalgebra/eigen/Traits.hpp
index f655af31..6558e1df 100644
--- a/src/amdis/linearalgebra/eigen/Traits.hpp
+++ b/src/amdis/linearalgebra/eigen/Traits.hpp
@@ -1,9 +1,10 @@
 #pragma once
 
-#include <Eigen/SparseCore>
-
 #include <dune/grid/common/partitionset.hh>
 #include <amdis/linearalgebra/Communication.hpp>
+#include <amdis/linearalgebra/eigen/MatrixSize.hpp>
+#include <amdis/linearalgebra/eigen/MatrixBackend.hpp>
+#include <amdis/linearalgebra/eigen/VectorBackend.hpp>
 
 namespace AMDiS
 {
@@ -13,11 +14,19 @@ namespace AMDiS
   template <class Basis, class T = double>
   struct BackendTraits
   {
-    using Mat = Eigen::SparseMatrix<T, Eigen::RowMajor>;
-    using Vec = Eigen::Matrix<T, Eigen::Dynamic, 1>;
-    using CoefficientType = T;
+    template <class Value>
+    using MatrixImpl = EigenSparseMatrix<Value, Eigen::RowMajor>;
+
+    template <class Value>
+    using VectorImpl = EigenVector<Value>;
+
+    using Mat = typename MatrixImpl<T>::BaseMatrix;
+    using Vec = typename VectorImpl<T>::BaseVector;
     using Comm = SequentialCommunication;
+
+    using CoefficientType = T;
     using PartitionSet = Dune::Partitions::All;
+    using SparsityPattern = MatrixSize;
   };
 
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/eigen/VectorBackend.hpp b/src/amdis/linearalgebra/eigen/VectorBackend.hpp
index 5efb9506..fe5ed9d7 100644
--- a/src/amdis/linearalgebra/eigen/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/eigen/VectorBackend.hpp
@@ -6,35 +6,37 @@
 
 #include <amdis/Output.hpp>
 #include <amdis/common/FakeContainer.hpp>
+#include <amdis/linearalgebra/VectorBase.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
 
 namespace AMDiS
 {
   /// The basic container that stores a base vector and a corresponding basis
   template <class T>
-  class VectorBackend
+  class EigenVector
+      : public VectorBase<EigenVector<T>>
   {
   public:
-    using Traits = T;
-
     /// The type of the base vector
-    using BaseVector = typename Traits::Vec;
+    using BaseVector = Eigen::Matrix<T, Eigen::Dynamic, 1>;
 
     /// The type of the elements of the DOFVector
     using value_type = typename BaseVector::Scalar;
 
+    /// The index/size - type
+    using size_type  = typename BaseVector::Index;
+
+  private:
     /// The type of the elements of the DOFVector
     using block_type = value_type;
 
     /// The underlying field type
     using field_type = typename Dune::FieldTraits<value_type>::field_type;
 
-    /// The index/size - type
-    using size_type  = typename BaseVector::Index;
-
   public:
     /// Constructor. Constructs new BaseVector.
     template <class Basis>
-    explicit VectorBackend(Basis const&) {}
+    explicit EigenVector(Basis const&) {}
 
     /// Return the data-vector \ref vector_
     BaseVector const& vector() const
@@ -49,7 +51,7 @@ namespace AMDiS
     }
 
     /// Return the current size of the \ref vector_
-    std::size_t size() const
+    size_type size() const
     {
       return vector_.size();
     }
@@ -64,66 +66,23 @@ namespace AMDiS
         vector_.setZero();
     }
 
-    void finish() { /* do nothing */ }
-    void synchronize() { /* do nothing */ }
-
-
-    /// Access the entry \p i of the \ref vector with read-access.
-    value_type const& at(size_type i) const
-    {
-      test_exit_dbg(i < vector_.size(),
-        "Index {} out of range [0,{})", i, vector_.size());
-      return vector_.coeff(i);
-    }
 
     /// Access the entry \p i of the \ref vector with write-access.
-    template <class Assign>
-    void insert(size_type i, value_type value, Assign assign)
+    template <class MultiIndex>
+    value_type& at(MultiIndex const& idx)
     {
-      test_exit_dbg(i < vector_.size(),
-        "Index {} out of range [0,{})", i, vector_.size());
-      assign(value, vector_.coeffRef(i));
+      const size_type i = flatMultiIndex(idx);
+      test_exit_dbg(i < size(), "Index {} out of range [0,{})", i, size());
+      return vector_.coeffRef(i);
     }
 
-    template <class IndexRange, class OutputIterator>
-    void gather(IndexRange const& localInd, OutputIterator buffer) const
-    {
-      for (size_type i : localInd)
-        *(buffer++) = vector_.coeff(i);
-    }
-
-    template <class IndexRange, class LocalVec, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, FakeContainer<bool,true>, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      for (size_type i : localInd)
-        assign(*vec_it++, vector_.coeffRef(i));
-    }
-
-    template <class IndexRange, class LocalVec, class MaskRange, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, MaskRange const& mask, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      auto mask_it = std::begin(mask);
-      auto ind_it = std::begin(localInd);
-      for (; vec_it != std::end(vec); ++vec_it, ++mask_it, ++ind_it) {
-        if (*mask_it)
-          assign(*vec_it, vector_.coeffRef(*ind_it));
-      }
-    }
-
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f) const
-    {
-      for (size_type i : localInd)
-        f(i, vector_.coeff(i));
-    }
-
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f)
+    /// Access the entry \p i of the \ref vector with read-access.
+    template <class MultiIndex>
+    value_type const& at(MultiIndex const& idx) const
     {
-      for (size_type i : localInd)
-        f(i, vector_.coeffRef(i));
+      const size_type i = flatMultiIndex(idx);
+      test_exit_dbg(i < size(), "Index {} out of range [0,{})", i, size());
+      return vector_.coeff(i);
     }
 
   private:
diff --git a/src/amdis/linearalgebra/istl/Constraints.hpp b/src/amdis/linearalgebra/istl/Constraints.hpp
index bbfed667..873a2a71 100644
--- a/src/amdis/linearalgebra/istl/Constraints.hpp
+++ b/src/amdis/linearalgebra/istl/Constraints.hpp
@@ -7,17 +7,15 @@
 
 namespace AMDiS
 {
-  template <class Traits>
-  struct Constraints<MatrixBackend<Traits>>
+  template <class T>
+  struct Constraints<ISTLBCRSMatrix<T>>
   {
-    using Matrix = MatrixBackend<Traits>;
-    using Vector = VectorBackend<Traits>;
+    using Matrix = ISTLBCRSMatrix<T>;
+    using Vector = ISTLBlockVector<T>;
 
     template <class BitVector>
     static void dirichletBC(Matrix& mat, Vector& sol, Vector& rhs, BitVector const& nodes, bool setDiagonal = true)
     {
-      using T = typename Matrix::value_type;
-
       // loop over the matrix rows
       for (std::size_t i = 0; i < mat.matrix().N(); ++i) {
         if (nodes[i]) {
diff --git a/src/amdis/linearalgebra/istl/MatrixBackend.hpp b/src/amdis/linearalgebra/istl/MatrixBackend.hpp
index a62e1135..1ae83e01 100644
--- a/src/amdis/linearalgebra/istl/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/istl/MatrixBackend.hpp
@@ -4,6 +4,7 @@
 #include <string>
 #include <memory>
 
+#include <dune/istl/bcrsmatrix.hh>
 #include <dune/istl/matrixindexset.hh>
 
 #include <amdis/Output.hpp>
@@ -11,14 +12,24 @@
 
 namespace AMDiS
 {
+  template <class T, class = void>
+  struct BlockMatrixType
+  {
+    using type = Dune::FieldMatrix<T,1,1>;
+  };
+
   template <class T>
-  class MatrixBackend
+  struct BlockMatrixType<T, typename T::field_type>
   {
-  public:
-    using Traits = T;
+    using type = T;
+  };
 
+  template <class T>
+  class ISTLBCRSMatrix
+  {
+  public:
     /// The matrix type of the underlying base matrix
-    using BaseMatrix = typename Traits::Mat;
+    using BaseMatrix = Dune::BCRSMatrix<typename BlockMatrixType<T>::type>;
 
     /// The type of the elements of the DOFMatrix
     using value_type = typename BaseMatrix::block_type;
@@ -29,7 +40,7 @@ namespace AMDiS
   public:
     /// Constructor. Constructs new BaseVector.
     template <class Basis>
-    explicit MatrixBackend(Basis const&, Basis const&) {}
+    explicit ISTLBCRSMatrix(Basis const&, Basis const&) {}
 
     /// Return the data-vector \ref vector
     BaseMatrix const& matrix() const
@@ -44,30 +55,10 @@ namespace AMDiS
     }
 
     /// create occupation pattern and apply it to the matrix
-    template <class RowBasis, class ColBasis>
-    void init(RowBasis const& rowBasis, ColBasis const& colBasis, SymmetryStructure symmetry)
+    template <class Pattern>
+    void init(Pattern const& pattern, SymmetryStructure symmetry)
     {
-      auto occupationPattern = Dune::MatrixIndexSet{rowBasis.dimension(), colBasis.dimension()};
-
-      auto rowLocalView = rowBasis.localView();
-      auto colLocalView = colBasis.localView();
-      for (const auto& element : elements(rowBasis.gridView())) {
-        rowLocalView.bind(element);
-        colLocalView.bind(element);
-
-        for (std::size_t i = 0; i < rowLocalView.size(); ++i) {
-          // The global index of the i-th vertex of the element
-          auto row = rowLocalView.index(i);
-          for (std::size_t j = 0; j < colLocalView.size(); ++j) {
-            // The global index of the j-th vertex of the element
-            auto col = colLocalView.index(j);
-            occupationPattern.add(row, col);
-          }
-        }
-      }
-
-      occupationPattern.exportIdx(matrix_);
-
+      pattern.applyTo(matrix_);
       symmetry_ = symmetry;
       initialized_ = true;
     }
diff --git a/src/amdis/linearalgebra/istl/Traits.hpp b/src/amdis/linearalgebra/istl/Traits.hpp
index fa368680..4372cb5f 100644
--- a/src/amdis/linearalgebra/istl/Traits.hpp
+++ b/src/amdis/linearalgebra/istl/Traits.hpp
@@ -3,54 +3,38 @@
 #include <dune/common/fmatrix.hh>
 #include <dune/common/fvector.hh>
 #include <dune/grid/common/partitionset.hh>
-#include <dune/istl/bcrsmatrix.hh>
-#include <dune/istl/bvector.hh>
 #include <dune/istl/operators.hh>
 #include <dune/istl/preconditioner.hh>
 #include <dune/istl/scalarproducts.hh>
 #include <dune/istl/solver.hh>
 
+#include <amdis/linearalgebra/SparsityPattern.hpp>
 #include <amdis/linearalgebra/istl/Communication.hpp>
 #include <amdis/linearalgebra/istl/Creators.hpp>
+#include <amdis/linearalgebra/istl/MatrixBackend.hpp>
+#include <amdis/linearalgebra/istl/VectorBackend.hpp>
 
 namespace AMDiS
 {
-  template <class T, class = void>
-  struct BlockMatrixType
-  {
-    using type = Dune::FieldMatrix<T,1,1>;
-  };
-
-  template <class T>
-  struct BlockMatrixType<T, typename T::field_type>
-  {
-    using type = T;
-  };
-
-  template <class T, class = void>
-  struct BlockVectorType
-  {
-    using type = Dune::FieldVector<T,1>;
-  };
-
-  template <class T>
-  struct BlockVectorType<T, typename T::field_type>
-  {
-    using type = T;
-  };
-
-
   /** Traits class for a linear solver for the system AX=B using an FE space described by a dune-functions Basis
    *  Contains typedefs specific to the ISTL backend.
    */
   template <class Basis, class T = double>
   struct BackendTraits
   {
-    using Mat             = Dune::BCRSMatrix<typename BlockMatrixType<T>::type>;
-    using Vec             = Dune::BlockVector<typename BlockVectorType<T>::type>;
-    using CoefficientType = T;
+    template <class Value>
+    using MatrixImpl = ISTLBCRSMatrix<Value>;
+    
+    template <class Value>
+    using VectorImpl = ISTLBlockVector<Value>;
+
+    using Mat             = typename MatrixImpl<T>::BaseMatrix;
+    using Vec             = typename VectorImpl<T>::BaseVector;
     using Comm            = ISTLCommunication_t<Basis>;
+
+    using CoefficientType = T;
     using PartitionSet    = Dune::Partitions::All;
+    using SparsityPattern = AMDiS::SparsityPattern<Basis, Basis>;
 
     using ScalProd        = Dune::ScalarProduct<Vec>;
     using LinOp           = Dune::AssembledLinearOperator<Mat, Vec, Vec>;
diff --git a/src/amdis/linearalgebra/istl/VectorBackend.hpp b/src/amdis/linearalgebra/istl/VectorBackend.hpp
index 378248a6..ab405cf4 100644
--- a/src/amdis/linearalgebra/istl/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/istl/VectorBackend.hpp
@@ -1,24 +1,40 @@
 #pragma once
 
+#include <dune/istl/bvector.hh>
+#include <dune/functions/backends/istlvectorbackend.hh>
+
 #include <amdis/Output.hpp>
 #include <amdis/common/FakeContainer.hpp>
+#include <amdis/linearalgebra/VectorBase.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
 
 namespace AMDiS
 {
+  template <class T, class = void>
+  struct BlockVectorType
+  {
+    using type = Dune::FieldVector<T,1>;
+  };
+
+  template <class T>
+  struct BlockVectorType<T, typename T::field_type>
+  {
+    using type = T;
+  };
+
 	template <class T>
-	class VectorBackend
+	class ISTLBlockVector
+      : public VectorBase<ISTLBlockVector<T>>
 	{
 	public:
-    using Traits = T;
-
     /// The vector type of the underlying base vector
-	  using BaseVector = typename Traits::Vec;
+	  using BaseVector = Dune::BlockVector<typename BlockVectorType<T>::type>;
 
     /// The type of the elements of the DOFVector
 	  using block_type = typename BaseVector::block_type;
 
     /// The type of the elements of the DOFVector
-    using value_type = block_type;
+    using value_type = T;
 
     /// The underlying field type
     using field_type = typename block_type::field_type;
@@ -29,7 +45,7 @@ namespace AMDiS
   public:
     /// Constructor. Constructs new BaseVector.
     template <class Basis>
-    explicit VectorBackend(Basis const&) {}
+    explicit ISTLBlockVector(Basis const&) {}
 
     /// Return the data-vector \ref vector
     BaseVector const& vector() const
@@ -49,74 +65,28 @@ namespace AMDiS
       return vector_.size();
     }
 
-    /// Resize the \ref vector_ to the size \p s
+    /// Resize the \ref vector_ to the size given by the \p sizeProvider
+    // NOTE: this resize works recursively on the hierarchy of the vector
     template <class SizeInfo>
-    void init(SizeInfo const& size, bool clear)
+    void init(SizeInfo const& sizeInfo, bool clear)
     {
-      vector_.resize(size_type(size));
+      Dune::Functions::istlVectorBackend(vector_).resize(sizeInfo);
       if (clear)
         vector_ = 0;
     }
 
-    void finish() { /* do nothing */ }
-    void synchronize() { /* so nothing */ }
-
-    /// Access the entry \p i of the \ref vector with read-access.
-    block_type const& at(size_type i) const
-    {
-      test_exit_dbg(i < vector_.size(),
-        "Index {} out of range [0,{})", i, vector_.size());
-      return vector_[i];
-    }
-
-    /// Access the entry \p i of the \ref vector with write-access.
-    template <class Assign>
-    void insert(size_type i, block_type const& value, Assign assign)
-    {
-      test_exit_dbg(i < vector_.size(),
-        "Index {} out of range [0,{})", i, vector_.size());
-      assign(value, vector_[i]);
-    }
-
-    template <class IndexRange, class OutputIterator>
-    void gather(IndexRange const& localInd, OutputIterator buffer) const
-    {
-      for (size_type i : localInd)
-        *buffer++ = vector_[i];
-    }
-
-    template <class IndexRange, class LocalVec, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, FakeContainer<bool,true>, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      for (size_type i : localInd)
-        assign(*vec_it++, vector_[i]);
-    }
-
-    template <class IndexRange, class LocalVec, class MaskRange, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, MaskRange const& mask, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      auto mask_it = std::begin(mask);
-      auto ind_it = std::begin(localInd);
-      for (; vec_it != std::end(vec); ++vec_it, ++mask_it, ++ind_it) {
-        if (*mask_it)
-          assign(*vec_it, vector_[*ind_it]);
-      }
-    }
-
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f) const
+    /// Access the entry \p idx of the \ref vector_ with write-access.
+    template <class MultiIndex>
+    value_type& at(MultiIndex const& idx)
     {
-      for (size_type i : localInd)
-        f(i, vector_[i]);
+      return Dune::Functions::istlVectorBackend(vector_)[idx];
     }
 
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f)
+    /// Access the entry \p idx of the \ref vector_ with read-access.
+    template <class MultiIndex>
+    value_type const& at(MultiIndex const& idx) const
     {
-      for (size_type i : localInd)
-        f(i, vector_[i]);
+      return Dune::Functions::istlVectorBackend(vector_)[idx];
     }
 
 	private:
diff --git a/src/amdis/linearalgebra/mtl/CMakeLists.txt b/src/amdis/linearalgebra/mtl/CMakeLists.txt
index 8b79796a..39165a47 100644
--- a/src/amdis/linearalgebra/mtl/CMakeLists.txt
+++ b/src/amdis/linearalgebra/mtl/CMakeLists.txt
@@ -6,6 +6,7 @@ install(FILES
     KrylovRunner.hpp
     MatrixBackend.hpp
     Preconditioner.hpp
+    SlotSize.hpp
     SolverPrecon.hpp
     Traits.hpp
     UmfpackRunner.hpp
diff --git a/src/amdis/linearalgebra/mtl/Constraints.hpp b/src/amdis/linearalgebra/mtl/Constraints.hpp
index 962bc51d..f15487fa 100644
--- a/src/amdis/linearalgebra/mtl/Constraints.hpp
+++ b/src/amdis/linearalgebra/mtl/Constraints.hpp
@@ -15,11 +15,11 @@
 
 namespace AMDiS
 {
-  template <class Traits>
-  struct Constraints<MatrixBackend<Traits>>
+  template <class T>
+  struct Constraints<MTLSparseMatrix<T>>
   {
-    using Matrix = MatrixBackend<Traits>;
-    using Vector = VectorBackend<Traits>;
+    using Matrix = MTLSparseMatrix<T>;
+    using Vector = MTLVector<T>;
 
     template <class BitVector>
     static void dirichletBC(Matrix& mat, Vector& sol, Vector& rhs, BitVector const& nodes, bool setDiagonal = true)
@@ -128,11 +128,11 @@ namespace AMDiS
     }
 
 
-    template <class T>
+    template <class Value>
     struct Triplet
     {
       std::size_t row, col;
-      T value;
+      Value value;
     };
 
     template <class Mat, class Vec, class BitVector, class Associations>
diff --git a/src/amdis/linearalgebra/mtl/MatrixBackend.hpp b/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
index 364bf7c9..78ce1d71 100644
--- a/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/mtl/MatrixBackend.hpp
@@ -5,24 +5,24 @@
 #include <string>
 #include <vector>
 
+#include <boost/numeric/mtl/matrix/compressed2D.hpp>
 #include <boost/numeric/mtl/matrix/inserter.hpp>
 #include <boost/numeric/mtl/utility/property_map.hpp>
 #include <boost/numeric/mtl/utility/range_wrapper.hpp>
 
 #include <amdis/Output.hpp>
 #include <amdis/linearalgebra/SymmetryStructure.hpp>
+#include <amdis/linearalgebra/mtl/SlotSize.hpp>
 
 namespace AMDiS
 {
   /// \brief The basic container that stores a base matrix
-  template <class TraitsType>
-  class MatrixBackend
+  template <class T>
+  class MTLSparseMatrix
   {
   public:
-    using Traits = TraitsType;
-
     /// The matrix type of the underlying base matrix
-    using BaseMatrix = typename Traits::Mat;
+    using BaseMatrix = mtl::compressed2D<T>;
 
     /// The type of the elements of the DOFMatrix
     using value_type = typename BaseMatrix::value_type;
@@ -30,13 +30,17 @@ namespace AMDiS
     /// The index/size - type
     using size_type = typename BaseMatrix::size_type;
 
+  private:
     /// The type of the inserter used when filling the matrix. NOTE: need not be public
     using Inserter = mtl::mat::inserter<BaseMatrix, mtl::operations::update_plus<value_type>>;
 
+    /// Type of the matrix non-zero pattern
+    using Pattern = SlotSize;
+
   public:
     /// Constructor. Constructs new BaseMatrix.
     template <class Basis>
-    explicit MatrixBackend(Basis const&, Basis const&) {}
+    explicit MTLSparseMatrix(Basis const& /*rowBasis*/, Basis const& /*colBasis*/) {}
 
     /// Return a reference to the data-matrix \ref matrix
     BaseMatrix& matrix()
@@ -53,16 +57,15 @@ namespace AMDiS
     }
 
     /// Create inserter. Assumes that no inserter is currently active on this matrix.
-    template <class RowBasis, class ColBasis>
-    void init(RowBasis const& rowBasis, ColBasis const& colBasis, SymmetryStructure symmetry)
+    void init(Pattern const& pattern, SymmetryStructure symmetry)
     {
       test_exit(!inserter_, "Matrix already in insertion mode!");
 
-      calculateSlotSize();
-      matrix_.change_dim(rowBasis.dimension(), colBasis.dimension());
+      std::size_t slotSize = pattern.avgRowSize(matrix_);
+      matrix_.change_dim(pattern.rows(), pattern.cols());
       set_to_zero(matrix_);
 
-      inserter_ = new Inserter(matrix_, slotSize_);
+      inserter_ = new Inserter(matrix_, slotSize);
       symmetry_ = symmetry;
     }
 
@@ -109,36 +112,20 @@ namespace AMDiS
       return matrix_.nnz();
     }
 
+    /// Symmetry of the matrix entries
     SymmetryStructure symmetry() const
     {
       return symmetry_;
     }
 
-  protected:
-    // Estimates the slot-size used in the inserter to reserve enough space per row.
-    void calculateSlotSize()
-    {
-      slotSize_ = 0;
-
-      if (num_rows(matrix_) != 0)
-        slotSize_ = int(double(matrix_.nnz()) / num_rows(matrix_) * 1.2);
-      if (slotSize_ < MIN_NNZ_PER_ROW)
-        slotSize_ = MIN_NNZ_PER_ROW;
-    }
-
   private:
-    /// The minimal number of nonzeros per row
-    static constexpr int MIN_NNZ_PER_ROW = 50;
-
     /// The data-matrix (can hold a new BaseMatrix or a pointer to external data
     BaseMatrix matrix_;
 
     /// A pointer to the inserter. Created in \ref init and destroyed in \ref finish
     Inserter* inserter_ = nullptr;
 
-    /// The size of the slots used to insert values per row
-    int slotSize_ = MIN_NNZ_PER_ROW;
-
+    /// Symmetry of the matrix entries
     SymmetryStructure symmetry_ = SymmetryStructure::unknown;
   };
 
diff --git a/src/amdis/linearalgebra/mtl/SlotSize.hpp b/src/amdis/linearalgebra/mtl/SlotSize.hpp
new file mode 100644
index 00000000..c04d8c31
--- /dev/null
+++ b/src/amdis/linearalgebra/mtl/SlotSize.hpp
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <cassert>
+#include <functional>
+#include <memory>
+#include <dune/common/math.hh>
+
+#include <amdis/Observer.hpp>
+#include <amdis/common/Index.hpp>
+#include <amdis/common/Math.hpp>
+
+namespace AMDiS
+{
+  class SlotSize
+      : private ObserverSequence<event::adapt,2>
+  {
+    struct BasisCallback
+    {
+      template <class Basis>
+      explicit BasisCallback(Basis const* basis)
+        : dimension([basis](){ return basis->dimension(); })
+        , maxSize([basis](){ return basis->localView().maxSize(); })
+      {}
+
+      std::function<std::size_t()> dimension;
+      std::function<std::size_t()> maxSize;
+    };
+
+  public:
+    template <class RowBasis, class ColBasis>
+    SlotSize(RowBasis const& rowBasis, ColBasis const& colBasis)
+      : ObserverSequence<event::adapt,2>(rowBasis, colBasis)
+      , rowBasis_(&rowBasis)
+      , colBasis_(&colBasis)
+      , surrounding_(Math::pow<RowBasis::GridView::dimension>(2) * Dune::factorial(int(RowBasis::GridView::dimension)))
+    {
+      updateImpl(event::adapt{true}, index_t<0>{});
+      updateImpl(event::adapt{true}, index_t<1>{});
+    }
+
+    /// Number of rows in the matrix
+    std::size_t rows() const
+    {
+      return rows_;
+    }
+
+    /// Number of columns in the matrix
+    std::size_t cols() const
+    {
+      return cols_;
+    }
+
+    /// Average number of non-zeros per row
+    /// In the first time this function is called, use the estRowSize,
+    /// otherwise take `1.5 * nnz/rows`
+    template <class Matrix>
+    std::size_t avgRowSize(Matrix const& matrix) const
+    {
+      assert(rows_ > 0 && cols_ > 0);
+      return matrix.nnz() > 0 ? 6*matrix.nnz() / (5*rows_) : estRowSize_;
+    }
+
+  protected:
+
+    // update of the row basis, just update the dimension
+    void updateImpl(event::adapt e, index_t<0> i) final 
+    { 
+      rows_ = rowBasis_.dimension(); 
+    }
+
+    // estimate the number of columns by multiplying the maximal node size with the 
+    // number of element surrounding a vertex. This number is approximated by the 
+    // number of simplices surrounding a vertex in a kuhn tringulation
+    void updateImpl(event::adapt e, index_t<1> i) final 
+    { 
+      cols_ = colBasis_.dimension();
+      estRowSize_ = std::min(cols_, colBasis_.maxSize() * surrounding_);
+    }
+
+  private:
+    BasisCallback rowBasis_;
+    BasisCallback colBasis_;
+
+    std::size_t rows_;
+    std::size_t cols_;
+    std::size_t estRowSize_;
+    std::size_t surrounding_;
+  };
+
+} // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/mtl/Traits.hpp b/src/amdis/linearalgebra/mtl/Traits.hpp
index f474fb63..e3fa936a 100644
--- a/src/amdis/linearalgebra/mtl/Traits.hpp
+++ b/src/amdis/linearalgebra/mtl/Traits.hpp
@@ -1,10 +1,10 @@
 #pragma once
 
-#include <boost/numeric/mtl/matrix/compressed2D.hpp>
-#include <boost/numeric/mtl/vector/dense_vector.hpp>
-
 #include <dune/grid/common/partitionset.hh>
 #include <amdis/linearalgebra/Communication.hpp>
+#include <amdis/linearalgebra/mtl/SlotSize.hpp>
+#include <amdis/linearalgebra/mtl/MatrixBackend.hpp>
+#include <amdis/linearalgebra/mtl/VectorBackend.hpp>
 
 namespace AMDiS
 {
@@ -14,11 +14,19 @@ namespace AMDiS
   template <class Basis, class T = double>
   struct BackendTraits
   {
-    using Mat = mtl::compressed2D<T>;
-    using Vec = mtl::dense_vector<T>;
-    using CoefficientType = T;
+    template <class Value>
+    using MatrixImpl = MTLSparseMatrix<Value>;
+
+    template <class Value>
+    using VectorImpl = MTLVector<Value>;
+
+    using Mat = typename MatrixImpl<T>::BaseMatrix;
+    using Vec = typename VectorImpl<T>::BaseVector;
     using Comm = SequentialCommunication;
+
+    using CoefficientType = T;
     using PartitionSet = Dune::Partitions::All;
+    using SparsityPattern = SlotSize;
   };
 
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/mtl/VectorBackend.hpp b/src/amdis/linearalgebra/mtl/VectorBackend.hpp
index c0108522..ada312c6 100644
--- a/src/amdis/linearalgebra/mtl/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/mtl/VectorBackend.hpp
@@ -1,38 +1,42 @@
 #pragma once
 
+#include <boost/numeric/mtl/vector/dense_vector.hpp>
+
 #include <dune/common/ftraits.hh>
 
 #include <amdis/Output.hpp>
 #include <amdis/common/FakeContainer.hpp>
+#include <amdis/linearalgebra/VectorBase.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
 
 namespace AMDiS
 {
   /// \brief The basic container that stores a base vector data
-  template <class TraitsType>
-  class VectorBackend
+  template <class T>
+  class MTLVector
+      : public VectorBase<MTLVector<T>>
   {
   public:
-    using Traits = TraitsType;
-
     /// The type of the base vector
-    using BaseVector = typename Traits::Vec;
+    using BaseVector = mtl::dense_vector<T>;
 
     /// The type of the elements of the DOFVector
     using value_type = typename BaseVector::value_type;
 
+    /// The index/size - type
+    using size_type  = typename BaseVector::size_type;
+
+  private:
     /// The type of the elements of the DOFVector
     using block_type = value_type;
 
     /// The underlying field type
     using field_type = typename Dune::FieldTraits<value_type>::field_type;
 
-    /// The index/size - type
-    using size_type  = typename BaseVector::size_type;
-
   public:
     /// Constructor. Constructs new BaseVector.
     template <class Basis>
-    explicit VectorBackend(Basis const&) {}
+    explicit MTLVector(Basis const&) {}
 
     /// Return the data-vector \ref vector_
     BaseVector const& vector() const
@@ -55,71 +59,29 @@ namespace AMDiS
 
     /// Resize the \ref vector_ to the size \p s
     template <class SizeInfo>
-    void init(SizeInfo const& size, bool clear)
+    void init(SizeInfo const& sizeInfo, bool clear)
     {
-      vector_.change_dim(size_type(size));
+      vector_.change_dim(sizeInfo({}));
       if (clear)
         set_to_zero(vector_);
     }
 
-    void finish() { /* do nothing */ }
-    void synchronize() { /* do nothing */ }
-
     /// Access the entry \p i of the \ref vector with read-access.
-    value_type const& at(size_type i) const
+    template <class MultiIndex>
+    value_type& at(MultiIndex const& idx)
     {
-      test_exit_dbg(i < mtl::vec::size(vector_),
-        "Index {} out of range [0,{})", i, mtl::vec::size(vector_));
+      const size_type i = flatMultiIndex(idx);
+      test_exit_dbg(i < size(),"Index {} out of range [0,{})", i, size());
       return vector_[i];
     }
 
-    template <class Assign>
-    void insert(size_type i, value_type const& value, Assign assign)
-    {
-      test_exit_dbg(i < mtl::vec::size(vector_),
-        "Index {} out of range [0,{})", i, mtl::vec::size(vector_));
-      assign(value, vector_[i]);
-    }
-
-    template <class IndexRange, class OutputIterator>
-    void gather(IndexRange const& localInd, OutputIterator buffer) const
-    {
-      for (size_type i : localInd)
-        *buffer++ = vector_[i];
-    }
-
-    template <class IndexRange, class LocalVec, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, FakeContainer<bool,true>, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      for (size_type i : localInd)
-        assign(*vec_it++, vector_[i]);
-    }
-
-    template <class IndexRange, class LocalVec, class MaskRange, class Assign>
-    void scatter(IndexRange const& localInd, LocalVec const& vec, MaskRange const& mask, Assign assign)
-    {
-      auto vec_it = std::begin(vec);
-      auto mask_it = std::begin(mask);
-      auto ind_it = std::begin(localInd);
-      for (; vec_it != std::end(vec); ++vec_it, ++mask_it, ++ind_it) {
-        if (*mask_it)
-          assign(*vec_it, vector_[*ind_it]);
-      }
-    }
-
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f) const
-    {
-      for (size_type i : localInd)
-        f(i, vector_[i]);
-    }
-
-    template <class IndexRange, class Func>
-    void forEach(IndexRange const& localInd, Func&& f)
+    /// Access the entry \p i of the \ref vector with read-access.
+    template <class MultiIndex>
+    value_type const& at(MultiIndex const& idx) const
     {
-      for (size_type i : localInd)
-        f(i, vector_[i]);
+      const size_type i = flatMultiIndex(idx);
+      test_exit_dbg(i < size(), "Index {} out of range [0,{})", i, size());
+      return vector_[i];
     }
 
   private:
diff --git a/src/amdis/linearalgebra/petsc/Communication.hpp b/src/amdis/linearalgebra/petsc/Communication.hpp
index 32d21214..8687cc9a 100644
--- a/src/amdis/linearalgebra/petsc/Communication.hpp
+++ b/src/amdis/linearalgebra/petsc/Communication.hpp
@@ -15,7 +15,7 @@
 
 namespace AMDiS
 {
-  template <class GlobalId, class LocalIndex>
+  template <class GlobalId, class SizeType>
   class DistributedCommunication
   {
   public:
@@ -26,8 +26,8 @@ namespace AMDiS
 #else
     struct IndexSet
     {
-      constexpr LocalIndex size() const { return size_; }
-      LocalIndex size_ = 0;
+      constexpr SizeType size() const { return size_; }
+      SizeType size_ = 0;
     };
 
     struct RemoteIndices {};
@@ -57,7 +57,7 @@ namespace AMDiS
     template <class Basis>
     void update(Basis const& basis)
     {
-      indexSet_.emplace();
+      indexSet_ = std::make_unique<IndexSet>();
 
 #if HAVE_MPI
       buildParallelIndexSet(basis, *indexSet_);
@@ -71,7 +71,7 @@ namespace AMDiS
     }
 
   protected:
-    Dune::Std::optional<IndexSet> indexSet_;
+    std::unique_ptr<IndexSet> indexSet_ = nullptr;
     RemoteIndices remoteIndices_;
     DofMap dofMap_;
   };
diff --git a/src/amdis/linearalgebra/petsc/Constraints.hpp b/src/amdis/linearalgebra/petsc/Constraints.hpp
index d00dba32..8dd91646 100644
--- a/src/amdis/linearalgebra/petsc/Constraints.hpp
+++ b/src/amdis/linearalgebra/petsc/Constraints.hpp
@@ -8,11 +8,11 @@
 
 namespace AMDiS
 {
-  template <class Traits>
-  struct Constraints<MatrixBackend<Traits>>
+  template <class DofMap>
+  struct Constraints<PetscMatrix<DofMap>>
   {
-    using Matrix = MatrixBackend<Traits>;
-    using Vector = VectorBackend<Traits>;
+    using Matrix = PetscMatrix<DofMap>;
+    using Vector = PetscVector<DofMap>;
 
     /// Dirichlet boundary conditions.
     /**
@@ -27,7 +27,7 @@ namespace AMDiS
     {
       thread_local std::vector<PetscInt> rows;
       rows.clear();
-      auto const& dofMap = mat.dofMap();
+      auto const& dofMap = mat.dofMap_;
       for (std::size_t i = 0; i < nodes.size(); ++i)
         if (nodes[i])
           rows.push_back(dofMap.global(i));
@@ -53,7 +53,7 @@ namespace AMDiS
       thread_local std::vector<PetscInt> rows, associated_rows;
       rows.clear();
       associated_rows.clear();
-      auto const& dofMap = mat.dofMap();
+      auto const& dofMap = mat.dofMap_;
       for (PetscInt i = 0; i < PetscInt(left.size()); ++i) {
         if (left[i]) {
           // get global row index
diff --git a/src/amdis/linearalgebra/petsc/MatrixBackend.hpp b/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
index 2c70d304..e72a33fb 100644
--- a/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixBackend.hpp
@@ -6,23 +6,20 @@
 
 #include <petscmat.h>
 
+#include <dune/common/timer.hh>
+
 #include <amdis/Output.hpp>
 #include <amdis/linearalgebra/SymmetryStructure.hpp>
-#include <amdis/linearalgebra/petsc/MatrixNnzStructure.hpp>
 
 namespace AMDiS
 {
   /// \brief The basic container that stores a base matrix
-  template <class T>
-  class MatrixBackend
+  template <class DofMap>
+  class PetscMatrix
   {
-    friend struct Constraints<MatrixBackend<T>>;
-
-    using Communication = typename T::Comm;
+    friend struct Constraints<PetscMatrix<DofMap>>;
 
   public:
-    using Traits = T;
-
     /// The matrix type of the underlying base matrix
     using BaseMatrix = ::Mat;
 
@@ -35,17 +32,17 @@ namespace AMDiS
   public:
     /// Constructor. Constructs new BaseMatrix.
     template <class Basis>
-    explicit MatrixBackend(Basis const& rowBasis, Basis const& /*colBasis*/)
-      : comm_(rowBasis.communicator())
+    explicit PetscMatrix(Basis const& rowBasis, Basis const& /*colBasis*/)
+      : dofMap_(rowBasis.communicator().dofMap())
     {}
 
     // disable copy and move operations
-    MatrixBackend(MatrixBackend const&) = delete;
-    MatrixBackend(MatrixBackend&&) = delete;
-    MatrixBackend& operator=(MatrixBackend const&) = delete;
-    MatrixBackend& operator=(MatrixBackend&&) = delete;
+    PetscMatrix(PetscMatrix const&) = delete;
+    PetscMatrix(PetscMatrix&&) = delete;
+    PetscMatrix& operator=(PetscMatrix const&) = delete;
+    PetscMatrix& operator=(PetscMatrix&&) = delete;
 
-    ~MatrixBackend()
+    ~PetscMatrix()
     {
       destroy();
     }
@@ -66,8 +63,8 @@ namespace AMDiS
     template <class RowIndex, class ColIndex>
     void insert(RowIndex const& r, ColIndex const& c, PetscScalar value)
     {
-      PetscInt row = dofMap().global(r);
-      PetscInt col = dofMap().global(c);
+      PetscInt row = dofMap_.global(r);
+      PetscInt col = dofMap_.global(c);
       MatSetValue(matrix_, row, col, value, ADD_VALUES);
     }
 
@@ -80,7 +77,7 @@ namespace AMDiS
 
       // create a vector of global indices from the local indices using the local-to-global map
       std::transform(localInd.begin(), localInd.end(), idx.begin(),
-        [&](auto const& mi) { return this->dofMap().global(mi); });
+        [this](auto const& mi) { return dofMap_.global(mi); });
 
       MatSetValues(matrix_, idx.size(), idx.data(), idx.size(), idx.data(), localMat.data(), ADD_VALUES);
     }
@@ -96,24 +93,19 @@ namespace AMDiS
 
       // create vectors of global indices from the local indices using the local-to-global map
       std::transform(rowLocalInd.begin(), rowLocalInd.end(), ri.begin(),
-        [&](auto const& mi) { return this->dofMap().global(mi); });
+        [this](auto const& mi) { return dofMap_.global(mi); });
       std::transform(colLocalInd.begin(), colLocalInd.end(), ci.begin(),
-        [&](auto const& mi) { return this->dofMap().global(mi); });
+        [this](auto const& mi) { return dofMap_.global(mi); });
 
       MatSetValues(matrix_, ri.size(), ri.data(), ci.size(), ci.data(), localMat.data(), ADD_VALUES);
     }
 
     /// Create and initialize the matrix
-    template <class RowBasis, class ColBasis>
-    void init(RowBasis const& rowBasis, ColBasis const& colBasis, SymmetryStructure symmetry)
+    template <class Pattern>
+    void init(Pattern const& pattern, SymmetryStructure symmetry)
     {
       Dune::Timer t;
 
-      // update the non-zeros structure of the matrix.
-      pattern_.update(rowBasis);
-      info(3, "  update pattern needed {} seconds", t.elapsed());
-      t.reset();
-
       // destroy an old matrix if created before
       destroy();
       info(3, "  destroy old matrix needed {} seconds", t.elapsed());
@@ -121,14 +113,14 @@ namespace AMDiS
 
       // create a MATAIJ or MATSEQAIJ matrix with provided sparsity pattern
       MatCreateAIJ(comm(),
-        dofMap().localSize(), dofMap().localSize(),
-        dofMap().globalSize(), dofMap().globalSize(),
-        0, pattern_.d_nnz().data(), 0, pattern_.o_nnz().data(), &matrix_);
+        dofMap_.localSize(), dofMap_.localSize(),
+        dofMap_.globalSize(), dofMap_.globalSize(),
+        0, pattern.d_nnz().data(), 0, pattern.o_nnz().data(), &matrix_);
 
       // keep sparsity pattern even if we delete a row / column with e.g. MatZeroRows
       MatSetOption(matrix_, MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
 
-      // set symmetriy properties of the matrix
+      // set symmetry properties of the matrix
       switch (symmetry) {
         case SymmetryStructure::spd:
           MatSetOption(matrix_, MAT_SPD, PETSC_TRUE);
@@ -171,12 +163,6 @@ namespace AMDiS
     }
 
   private:
-    // The local-to-global map
-    auto const& dofMap() const
-    {
-      return comm_.dofMap();
-    }
-
     // An MPI Communicator or PETSC_COMM_SELF
     MPI_Comm comm() const
     {
@@ -195,11 +181,11 @@ namespace AMDiS
     }
 
   private:
-    Communication const& comm_;
+    // The local-to-global map
+    DofMap const& dofMap_;
 
     /// The data-matrix
     Mat matrix_;
-    MatrixNnzStructure pattern_;
 
     bool initialized_ = false;
   };
diff --git a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
index 1a83ec3d..215d8aff 100644
--- a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.hpp
@@ -3,6 +3,9 @@
 #include <algorithm>
 #include <vector>
 
+#include <amdis/Observer.hpp>
+#include <amdis/common/Index.hpp>
+
 #if HAVE_MPI
 #include <amdis/common/parallel/Communicator.hpp>
 #endif
@@ -10,9 +13,19 @@
 namespace AMDiS
 {
   /// Sparsity pattern used to create PETSc matrices
+  template <class RowBasis, class ColBasis = RowBasis>
   class MatrixNnzStructure
+      : private ObserverSequence<event::adapt,2>
   {
   public:
+    MatrixNnzStructure(RowBasis const& rowBasis, ColBasis const& colBasis)
+      : ObserverSequence<event::adapt,2>(rowBasis, colBasis)
+      , rowBasis_(&rowBasis)
+      , colBasis_(&colBasis)
+    {
+      update();
+    }
+
     // Return Number of nonzeros in the diagonal part (owner part)
     std::vector<PetscInt> const& d_nnz() const
     {
@@ -25,12 +38,34 @@ namespace AMDiS
       return onnz_;
     }
 
-    /// Calculate the matrix pattern from the local pattern of a basis.
-    // NOTE: this assumes a square matrix with row-basis = col-basis.
-    template <class Basis>
-    void update(Basis const& basis);
+  protected:
+
+    void updateImpl(event::adapt e, index_t<0> i) override { updateImpl2(e,i); }
+    void updateImpl(event::adapt e, index_t<1> i) override { updateImpl2(e,i); }
 
   private:
+
+    // Track for each basis wether updated and if both are, call updateImpl3()
+    template <std::size_t I>
+    void updateImpl2(event::adapt, index_t<I>)
+    {
+      assert(!updateCounter_.test(I));
+      updateCounter_.set(I);
+
+      if (updateCounter_.all()) {
+        update();
+        updateCounter_.reset();
+      }
+    }
+
+    // Update pattern when basis is updated
+    void update();
+
+  private:
+    RowBasis const* rowBasis_;
+    ColBasis const* colBasis_;
+    std::bitset<2> updateCounter_ = 0;
+
     std::vector<PetscInt> dnnz_; //< number of nonzeros in the diagonal part (owner part)
     std::vector<PetscInt> onnz_; //< number of nonzeros in the off-diagonal part (overlap part)
 
diff --git a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
index cf7a5070..9231ca33 100644
--- a/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
+++ b/src/amdis/linearalgebra/petsc/MatrixNnzStructure.inc.hpp
@@ -16,19 +16,12 @@
 
 namespace AMDiS {
 
-template <class Basis>
-void MatrixNnzStructure::update(Basis const& basis)
+template <class RB, class CB>
+void MatrixNnzStructure<RB,CB>::update()
 {
-  unsigned long newChangeIndex = changeIndex(basis.gridView().grid());
-  bool gridChanged = newChangeIndex > changeIndex_;
-  changeIndex_ = newChangeIndex;
-
-  // update is not necessary
-  if (initialized_ && !gridChanged)
-    return;
-
   Dune::Timer t;
 
+  auto const& basis = *rowBasis_; // TODO: generalize to row != col basis
   auto const& dofMap = basis.communicator().dofMap();
   std::size_t localSize = dofMap.localSize();
   test_exit(localSize > 0, "Local domain has no owned DOFs!");
@@ -185,8 +178,7 @@ void MatrixNnzStructure::update(Basis const& basis)
 
 #endif // HAVE_MPI
 
-  initialized_ = true;
-  msg("update MatrixNnzStructure need {} sec", t.elapsed());
+  info(2,"update MatrixNnzStructure need {} sec", t.elapsed());
 }
 
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/petsc/Traits.hpp b/src/amdis/linearalgebra/petsc/Traits.hpp
index 9272533b..f0c275bb 100644
--- a/src/amdis/linearalgebra/petsc/Traits.hpp
+++ b/src/amdis/linearalgebra/petsc/Traits.hpp
@@ -7,6 +7,9 @@
 
 #include <dune/grid/common/partitionset.hh>
 #include <amdis/linearalgebra/petsc/Communication.hpp>
+#include <amdis/linearalgebra/petsc/MatrixNnzStructure.hpp>
+#include <amdis/linearalgebra/petsc/MatrixBackend.hpp>
+#include <amdis/linearalgebra/petsc/VectorBackend.hpp>
 
 namespace AMDiS
 {
@@ -20,9 +23,17 @@ namespace AMDiS
 
     using Mat = ::Mat;
     using Vec = ::Vec;
-    using CoefficientType = PetscScalar;
     using Comm = DistributedCommunication_t<Basis>;
+
+    template <class>
+    using MatrixImpl = PetscMatrix<typename Comm::DofMap>;
+
+    template <class>
+    using VectorImpl = PetscVector<typename Comm::DofMap>;
+
+    using CoefficientType = PetscScalar;
     using PartitionSet = Dune::Partitions::Interior;
+    using SparsityPattern = MatrixNnzStructure<Basis>;
   };
 
 } // end namespace AMDiS
diff --git a/src/amdis/linearalgebra/petsc/VectorBackend.hpp b/src/amdis/linearalgebra/petsc/VectorBackend.hpp
index 3634c607..a8d67718 100644
--- a/src/amdis/linearalgebra/petsc/VectorBackend.hpp
+++ b/src/amdis/linearalgebra/petsc/VectorBackend.hpp
@@ -4,28 +4,25 @@
 
 #include <dune/common/ftraits.hh>
 #include <dune/common/shared_ptr.hh>
+#include <dune/functions/functionspacebases/flatmultiindex.hh>
 
 #include <amdis/Output.hpp>
 #include <amdis/common/FakeContainer.hpp>
-#include <amdis/functions/Interpolate.hpp>
 #include <amdis/operations/Assigner.hpp>
+#include <amdis/typetree/MultiIndex.hpp>
 
 namespace AMDiS
 {
   /// The basic container that stores a base vector data
-  template <class T>
-  class VectorBackend
+  template <class DofMap>
+  class PetscVector
   {
-    using Communication = typename T::Comm;
-
     template <class A>
     using AssignMode = std::conditional_t<std::is_same<A,Assigner::plus_assign>::value,
       std::integral_constant<::InsertMode, ADD_VALUES>,
       std::integral_constant<::InsertMode, INSERT_VALUES>>;
 
   public:
-    using Traits = T;
-
     /// The type of the base vector
     using BaseVector = ::Vec;
 
@@ -38,19 +35,20 @@ namespace AMDiS
   public:
     /// Constructor. Constructs new BaseVector.
     template <class Basis>
-    explicit VectorBackend(Basis const& basis)
-      : comm_(Dune::stackobject_to_shared_ptr(basis.communicator()))
+    explicit PetscVector(Basis const& basis)
+      : dofMap_(basis.communicator().dofMap())
     {}
 
     /// Move constructor
-    VectorBackend(VectorBackend&& other)
+    PetscVector(PetscVector&& other)
+      : dofMap_(other.dofMap_)
     {
       swap(*this, other);
     }
 
     /// Copy constructor
-    VectorBackend(VectorBackend const& other)
-      : comm_(other.comm_)
+    PetscVector(PetscVector const& other)
+      : dofMap_(other.dofMap_)
       , initialized_(other.initialized_)
     {
       if (other.initialized_) {
@@ -60,22 +58,22 @@ namespace AMDiS
     }
 
     /// Destructor
-    ~VectorBackend()
+    ~PetscVector()
     {
       destroy();
     }
 
     /// Move assignment operator
-    VectorBackend& operator=(VectorBackend&& other)
+    PetscVector& operator=(PetscVector&& other)
     {
       swap(*this, other);
       return *this;
     }
 
     /// Copy assignment operator
-    VectorBackend& operator=(VectorBackend const& other)
+    PetscVector& operator=(PetscVector const& other)
     {
-      return *this = VectorBackend(other);
+      return *this = PetscVector(other);
     }
 
     /// Return the data-vector \ref vector_
@@ -93,13 +91,13 @@ namespace AMDiS
     /// Return the number of entries in the local part of the vector
     std::size_t localSize() const
     {
-      return dofMap().localSize();
+      return dofMap_.localSize();
     }
 
     /// Return the number of entries in the global vector
     std::size_t globalSize() const
     {
-      return dofMap().globalSize();
+      return dofMap_.globalSize();
     }
 
     /// Resize the \ref vector_ to the size \p s
@@ -120,8 +118,8 @@ namespace AMDiS
         VecGetLocalSize(vector_, &localSize);
 
         // re-create the vector
-        if (std::size_t(localSize) != dofMap().localSize() ||
-            std::size_t(globalSize) != dofMap().globalSize()) {
+        if (std::size_t(localSize) != dofMap_.localSize() ||
+            std::size_t(globalSize) != dofMap_.globalSize()) {
           destroy();
           create();
           info(3, "  destroy old and create new vector needed {} seconds", t.elapsed());
@@ -157,20 +155,21 @@ namespace AMDiS
 
     /// Access the entry \p i of the \ref vector with read-only-access.
     // [[not collective]]
-    PetscScalar at(std::size_t i) const
+    template <class MultiIndex>
+    PetscScalar at(MultiIndex const& idx) const
     {
       PetscScalar y = 0;
-      gather(std::array<std::size_t,1>{i}, &y);
+      gather(std::array<MultiIndex,1>{idx}, &y);
       return y;
     }
 
     /// Access the entry \p i of the \ref vector with write-access.
     // [[not collective]]
-    template <class Assign>
-    void insert(std::size_t dof, PetscScalar value, Assign)
+    template <class MultiIndex, class Assign>
+    void insert(MultiIndex const& dof, PetscScalar value, Assign)
     {
       assert(initialized_);
-      VecSetValue(vector_, dofMap().global(dof), value, AssignMode<Assign>::value);
+      VecSetValue(vector_, dofMap_.global(flatMultiIndex(dof)), value, AssignMode<Assign>::value);
     }
 
     /// Collect all values from this vector to indices given by `localInd` and store it into the output buffer.
@@ -201,7 +200,7 @@ namespace AMDiS
       auto ind_it = std::begin(localInd);
       auto mask_it = std::begin(mask);
       for (; ind_it != std::end(localInd); ++mask_it, ++ind_it)
-        globalInd.push_back(*mask_it ? dofMap().global(*ind_it) : -1);
+        globalInd.push_back(*mask_it ? dofMap_.global(flatMultiIndex(*ind_it)) : -1);
 
       if (! std::is_same<MaskRange, FakeContainer<bool,true>>::value)
         VecSetOption(vector_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
@@ -226,13 +225,14 @@ namespace AMDiS
 
       for (auto const& dof : localInd)
       {
-        if (dofMap().owner(dof)) {
+        size_type i = flatMultiIndex(dof);
+        if (dofMap_.owner(i)) {
           // the index is a purely local entry
-          f(dof, ptr[dofMap().dofToLocal(dof)]);
+          f(dof, ptr[dofMap_.dofToLocal(i)]);
         }
         else {
           // ghost entries are stored at the end of the array
-          f(dof, ptr[dofMap().localSize() + dofMap().dofToGhost(dof)]);
+          f(dof, ptr[dofMap_.localSize() + dofMap_.dofToGhost(i)]);
         }
       }
 
@@ -240,6 +240,20 @@ namespace AMDiS
       VecGhostRestoreLocalForm(vector_, &localGhostedVec);
     }
 
+    template <class Func>
+    void forEach(Func&& f) 
+    {
+      forEach(mappedRangeView(Dune::range(localSize()),
+        [](auto i) { return Dune::Functions::FlatMultiIndex<decltype(i)>{i}; }), FWD(f));
+    }
+
+    template <class Func>
+    void forEach(Func&& f) const 
+    {
+      forEach(mappedRangeView(Dune::range(localSize()),
+        [](auto i) { return Dune::Functions::FlatMultiIndex<decltype(i)>{i}; }), FWD(f));
+    }
+
 
     /// Set all entries to \p value, including the ghost entries
     // [[not collective]]
@@ -265,20 +279,14 @@ namespace AMDiS
       VecGhostRestoreLocalForm(vector_, &localGhostedVec);
     }
 
-    friend void swap(VectorBackend& lhs, VectorBackend& rhs)
+    friend void swap(PetscVector& lhs, PetscVector& rhs)
     {
-      std::swap(lhs.comm_, rhs.comm_);
+      assert(&lhs.dofMap_ == &rhs.dofMap_);
       std::swap(lhs.vector_, rhs.vector_);
       std::swap(lhs.initialized_, rhs.initialized_);
     }
 
   private:
-    // The local-to-global map
-    auto const& dofMap() const
-    {
-      return comm_->dofMap();
-    }
-
     // An MPI Communicator or PETSC_COMM_SELF
     MPI_Comm comm() const
     {
@@ -293,7 +301,7 @@ namespace AMDiS
     void create()
     {
       VecCreateGhost(comm(),
-        dofMap().localSize(), dofMap().globalSize(), dofMap().ghostSize(), dofMap().ghostIndices().data(),
+        dofMap_.localSize(), dofMap_.globalSize(), dofMap_.ghostSize(), dofMap_.ghostIndices().data(),
         &vector_);
     }
 
@@ -307,7 +315,8 @@ namespace AMDiS
     }
 
   private:
-    std::shared_ptr<Communication const> comm_;
+    // The local-to-global map
+    DofMap const& dofMap_;
 
     /// The data-vector
     mutable Vec vector_ = nullptr;
diff --git a/src/amdis/typetree/MultiIndex.hpp b/src/amdis/typetree/MultiIndex.hpp
index 62f9a087..fb997f13 100644
--- a/src/amdis/typetree/MultiIndex.hpp
+++ b/src/amdis/typetree/MultiIndex.hpp
@@ -20,4 +20,13 @@ namespace AMDiS
     return idx[0];
   }
 
+  template <class MultiIndex>
+  void multiIndexPushFront(MultiIndex& M, std::size_t M0)
+  {
+    M.resize(M.size() + 1);
+    for (std::size_t i = M.size()-1; i > 0; --i)
+      M[i] = M[i-1];
+    M[0] = M0;
+  }
+
 } // end namespace AMDiS
diff --git a/test/DOFVectorTest.cpp b/test/DOFVectorTest.cpp
index e673e38b..ee8feb7b 100644
--- a/test/DOFVectorTest.cpp
+++ b/test/DOFVectorTest.cpp
@@ -22,33 +22,38 @@ using namespace Dune::Functions::BasisFactory;
 template <class B, class T>
 void test_dofvector(DOFVector<B,T>& vec)
 {
-  using size_type = typename DOFVector<B,T>::GlobalBasis::LocalView::size_type;
-  using value_type = typename DOFVector<B,T>::value_type;
+  using MultiIndex = typename B::MultiIndex;
 
   auto const& basis = *vec.basis();
-  AMDIS_TEST( vec.localSize() == basis.dimension() );
-  vec.resizeZero();
 
-  vec.init(false);
-  vec.insert(0, value_type(1));
+  vec.init(true);
+  AMDIS_TEST_EQ(vec.localSize(), basis.size());
+
+  vec.insert(MultiIndex{0}, T(1));
   vec.finish();
 
-  value_type min(10);
-  value_type max(-10);
-  auto lv = basis.localView();
-  auto const& gv = basis.gridView();
-  for (auto const& e : elements(gv))
-  {
-    lv.bind(e);
-    for (size_type i = 0; i < lv.size(); ++i)
-    {
-      auto value = vec.at(lv.index(i));
-      min = std::min(min, value);
-      max = std::max(max, value);
-    }
-  }
-  AMDIS_TEST( min == T(0) || vec.localSize() == 1 );
-  AMDIS_TEST( max == T(1) );
+  AMDIS_TEST_EQ(vec.at(MultiIndex{0}), T(1));
+
+  T min(10);
+  T max(-10);
+  vec.forEach([&min,&max](auto, auto value) {
+    min = std::min(min, value);
+    max = std::max(max, value);
+  });
+
+  if (vec.localSize() > 1) 
+    AMDIS_TEST_EQ(min, T(0));
+  AMDIS_TEST_EQ(max, T(1));
+
+  // interpolate constant function on DOFVector
+  vec << T(2);
+  AMDIS_TEST_EQ(vec.at(MultiIndex{0}), T(2));
+
+  vec.interpolate(T(3));
+  AMDIS_TEST_EQ(vec.at(MultiIndex{0}), T(3));
+
+  vec.interpolate_noalias(T(4));
+  AMDIS_TEST_EQ(vec.at(MultiIndex{0}), T(4));
 }
 
 int main(int argc, char** argv)
@@ -97,15 +102,15 @@ int main(int argc, char** argv)
     // Conversion from Dune::Functions::DefaultGlobalBasis
     auto vec2 = makeDOFVector(makeBasis(gridView, preBasis));
 
-    test_dofvector(vec1);
     for (auto const& e : elements(gridView))
       grid.mark(1, e);
+
     grid.preAdapt();
     grid.adapt();
     grid.postAdapt();
-    std::size_t newSize = basis.dimension();
-    AMDIS_TEST_EQ(vec1.localSize(), newSize);
-    AMDIS_TEST_EQ(vec2.localSize(), newSize);
+
+    test_dofvector(vec1);
+    test_dofvector(vec2);
   }
 
   report_errors();
diff --git a/test/DiscreteFunctionTest.cpp b/test/DiscreteFunctionTest.cpp
index 58d51d00..048803c8 100644
--- a/test/DiscreteFunctionTest.cpp
+++ b/test/DiscreteFunctionTest.cpp
@@ -63,8 +63,8 @@ int main(int argc, char** argv)
   auto& U_m = *prob.solutionVector();
 
 #if DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-  DiscreteFunction u0_c(U_c);
-  DiscreteFunction u0_m(U_m);
+  DiscreteFunction u0_c(U_c.coefficients(), *U_c.basis());
+  DiscreteFunction u0_m(U_m.coefficients(), *U_m.basis());
 #endif
   auto u1_c = makeDiscreteFunction(U_c);
   auto u1_m = makeDiscreteFunction(U_m);
diff --git a/test/ExpressionsTest.cpp b/test/ExpressionsTest.cpp
index d8183517..aa1ecae2 100644
--- a/test/ExpressionsTest.cpp
+++ b/test/ExpressionsTest.cpp
@@ -94,7 +94,7 @@ int main(int argc, char** argv)
 
   // integration of expressions
 
-  auto gv = u.basis()->gridView();
+  auto gv = u.basis().gridView();
 
   DUNE_UNUSED auto int1 = integrate(op1, gv, 5);
   DUNE_UNUSED auto int2 = integrate(op2, gv, 5);
diff --git a/test/IntegrateTest.cpp b/test/IntegrateTest.cpp
index ea82e2c9..adb28a08 100644
--- a/test/IntegrateTest.cpp
+++ b/test/IntegrateTest.cpp
@@ -24,7 +24,7 @@ int main(int argc, char** argv)
   prob.initialize(INIT_ALL);
 
   auto u = prob.solution(0);
-  auto gv = u.basis()->gridView();
+  auto gv = u.basis().gridView();
 
   u << 1.0;
   double i1 = integrate(1.0, gv);
diff --git a/test/ObserverTest.cpp b/test/ObserverTest.cpp
index 8f82e888..93e66256 100644
--- a/test/ObserverTest.cpp
+++ b/test/ObserverTest.cpp
@@ -63,8 +63,8 @@ class B
 {
 public:
   B(std::shared_ptr<A> a)
-    : Observer<event::fooEvent>(*a)
-    , Observer<event::bazEvent>(*a)
+    : Observer<event::fooEvent>(a)
+    , Observer<event::bazEvent>(a)
     , a_(a)
   {}
 
@@ -92,8 +92,8 @@ class C
 {
 public:
   C(std::shared_ptr<B> b)
-    : Observer<event::barEvent>(*b->a())
-    , Observer<event::bazEvent>(*b)
+    : Observer<event::barEvent>(b->a())
+    , Observer<event::bazEvent>(b)
   {}
 
   void updateImpl(event::barEvent) override
@@ -128,8 +128,8 @@ class E
 {
 public:
   E(std::shared_ptr<A> a, std::shared_ptr<D> d)
-      : Observer<event::fooEvent>(*a)
-      , Observer<event::barEvent>(*d)
+      : Observer<event::fooEvent>(a)
+      , Observer<event::barEvent>(d)
   {}
 
   void updateImpl(event::fooEvent) override
diff --git a/test/PETScCommTest.cpp b/test/PETScCommTest.cpp
index 8f4b2df1..e712e6d8 100644
--- a/test/PETScCommTest.cpp
+++ b/test/PETScCommTest.cpp
@@ -35,7 +35,7 @@ void test_basis(Basis const& basis, std::string gridName, std::string basisName)
   using Comm = typename Traits::Comm;
 
   auto comm = CommunicationCreator<Comm>::create(basis, "communication");
-  auto const& dofMap = comm->dofMap();
+  auto const& dofMap = comm.dofMap();
 
   using GlobalIndex = typename Comm::DofMap::GlobalIndex;
   std::vector<std::vector<GlobalIndex>> data(world.size());
diff --git a/test/ProblemStatTest.cpp b/test/ProblemStatTest.cpp
index 4d99b534..5f3563fc 100644
--- a/test/ProblemStatTest.cpp
+++ b/test/ProblemStatTest.cpp
@@ -31,6 +31,7 @@ void test()
   // use T as coefficient type
   using Param = DefaultProblemTraits<Basis, T>;
 
+  msg("Test<{}>", __PRETTY_FUNCTION__);
   ProblemStat<Param> prob("ellipt", grid, basis);
   prob.initialize(INIT_ALL);
   prob.boundaryManager()->setBoxBoundary({1,1,2,2});
@@ -42,12 +43,12 @@ void test()
 
   AdaptInfo adaptInfo("adapt");
 
-  // test copy constructor of problem
+  msg("  test copy constructor of problem");
   auto prob2(prob);
   AdaptStationary adaptStat2("adapt", prob2, adaptInfo);
   adaptStat2.adapt();
 
-  // test move constructor of problem
+  msg("  test move constructor of problem");
   auto prob3(std::move(prob2));
   AdaptStationary adaptStat3("adapt", prob3, adaptInfo);
   adaptStat3.adapt();
@@ -57,19 +58,19 @@ int main(int argc, char** argv)
 {
   Environment env(argc, argv);
 
-#if !HAVE_PETSC || PETSC_USE_REAL_SINGLE
+#if !AMDIS_HAS_PETSC || PETSC_USE_REAL_SINGLE
   test<float>();
 #endif
 
-#if !HAVE_PETSC || PETSC_USE_REAL_DOUBLE
+#if !AMDIS_HAS_PETSC || PETSC_USE_REAL_DOUBLE
   test<double>();
 #endif
 
-#if !HAVE_PETSC
+#if !AMDIS_HAS_PETSC
   test<long double>();
 #endif
 
-#if HAVE_QUADMATH && (!HAVE_PETSC || PETSC_USE_REAL___FLOAT128)
+#if HAVE_QUADMATH && (!AMDIS_HAS_PETSC || PETSC_USE_REAL___FLOAT128) && (!AMDIS_HAS_EIGEN)
   test<Dune::Float128>();
 #endif
 
-- 
GitLab