diff --git a/examples/ellipt.cc b/examples/ellipt.cc
index ddaad29b138ebdfd9a486c6f5f910851025bc160..6baf47bfb8cbba1adf2a4ffc10a5cb46f742a29f 100644
--- a/examples/ellipt.cc
+++ b/examples/ellipt.cc
@@ -32,6 +32,8 @@ int main(int argc, char** argv)
   auto opForce = makeOperator(tag::test{}, [](auto const& x) { return -1.0; }, 0);
   prob.addVectorOperator(opForce, _0);
 
+  auto opForce2 = makeOperator(tag::test{}, [](auto const& x) { return -2.0; }, 0);
+  prob.addVectorOperator(BoundaryType{0}, opForce2, _0);
 
   // set boundary condition
   auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary
diff --git a/src/amdis/Assembler.hpp b/src/amdis/Assembler.hpp
index c5f6ab4e59cb64e178cdc8ad6cd4bc1e96612d7f..8473ac32278e44489042ffa87e253b582653c7cf 100644
--- a/src/amdis/Assembler.hpp
+++ b/src/amdis/Assembler.hpp
@@ -8,7 +8,7 @@
 
 #include <amdis/DirichletBC.hpp>
 #include <amdis/LinearAlgebra.hpp>
-#include <amdis/LocalAssemblerBase.hpp>
+#include <amdis/LocalAssemblerList.hpp>
 #include <amdis/common/Mpl.hpp>
 #include <amdis/common/TypeDefs.hpp>
 
@@ -54,6 +54,8 @@ namespace AMDiS
         SystemVectorType& rhs,
         bool asmMatrix, bool asmVector) const;
 
+    /// Assemble operators on an element, by passing the element/intersection to
+    /// `elementAssembler` functor.
     template <class Element, class Operators, class ElementAssembler>
     void assembleElementOperators(
         Element const& element,
@@ -70,14 +72,14 @@ namespace AMDiS
         bool asmMatrix, bool asmVector) const;
 
 
-    /// Return whether the matrix-block needs to be assembled
+    /// Return the element the LocalViews are bound to
     template <class LocalView0, class... LovalViews>
     auto const& getElement(LocalView0 const& localView, LovalViews const&...) const
     {
       return localView.element();
     }
 
-    /// Return whether the matrix-block needs to be assembled
+    /// Return the gridView the localViews are bound to
     template <class LocalView0, class... LovalViews>
     auto const& getGridView(LocalView0 const& localView, LovalViews const&...) const
     {
diff --git a/src/amdis/Assembler.inc.hpp b/src/amdis/Assembler.inc.hpp
index 1cf4a4eaf39f721d145601816fee68c248095c87..05501f75e98c37487a374f2bf227eab6e15bf3a0 100644
--- a/src/amdis/Assembler.inc.hpp
+++ b/src/amdis/Assembler.inc.hpp
@@ -45,12 +45,12 @@ void Assembler<Traits>::assemble(
       rowLocalView.bind(element);
 
       auto& rhsOp = rhsOperators_[rowNode];
-      if (rhsOp.assemble(asmVector) && !rhsOp.empty()) {
+      if (rhsOp.doAssemble(asmVector) && !rhsOp.empty()) {
         rhsOp.bind(element, geometry);
 
         auto vecAssembler = [&](auto const& context, auto& operator_list) {
           for (auto scaled : operator_list)
-            scaled.op->assemble(context, elementVector, rowLocalView.tree());
+            scaled.op->assemble(context, rowLocalView.tree(), elementVector);
         };
 
         this->assembleElementOperators(element, rhsOp, vecAssembler);
@@ -59,7 +59,7 @@ void Assembler<Traits>::assemble(
       AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
       {
         auto& matOp = matrixOperators_[rowNode][colNode];
-        if (matOp.assemble(asmMatrix) && !matOp.empty()) {
+        if (matOp.doAssemble(asmMatrix) && !matOp.empty()) {
           auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
           auto colLocalView = colBasis.localView();
           colLocalView.bind(element);
@@ -68,7 +68,7 @@ void Assembler<Traits>::assemble(
 
           auto matAssembler = [&](auto const& context, auto& operator_list) {
             for (auto scaled : operator_list)
-              scaled.op->assemble(context, elementMatrix, rowLocalView.tree(), colLocalView.tree());
+              scaled.op->assemble(context, rowLocalView.tree(), colLocalView.tree(), elementMatrix);
           };
 
           this->assembleElementOperators(element, matOp, matAssembler);
@@ -121,10 +121,10 @@ template <class Traits>
 void Assembler<Traits>::assembleElementOperators(
     Element const& element,
     Operators& operators,
-    ElementAssembler const& elementAssembler) const
+    ElementAssembler const& localAssembler) const
 {
   // assemble element operators
-  elementAssembler(element, operators.element);
+  localAssembler(element, operators.element);
 
   // assemble intersection operators
   if (!operators.intersection.empty()
@@ -132,9 +132,9 @@ void Assembler<Traits>::assembleElementOperators(
   {
     for (auto const& intersection : intersections(globalBasis_.gridView(), element)) {
       if (intersection.boundary())
-        elementAssembler(intersection, operators.boundary);
+        localAssembler(intersection, operators.boundary);
       else
-        elementAssembler(intersection, operators.intersection);
+        localAssembler(intersection, operators.intersection);
     }
   }
 }
@@ -191,14 +191,14 @@ std::size_t Assembler<Traits>::finishMatrixVector(
   {
     auto rowBasis = Dune::Functions::subspaceBasis(globalBasis_, rowTreePath);
     auto& rhsOp = rhsOperators_[rowNode];
-    if (rhsOp.assemble(asmVector))
+    if (rhsOp.doAssemble(asmVector))
       rhsOp.assembled = true;
 
     AMDiS::forEachNode_(localView.tree(), [&,this](auto const& colNode, auto colTreePath)
     {
       auto colBasis = Dune::Functions::subspaceBasis(globalBasis_, colTreePath);
       auto& matOp = matrixOperators_[rowNode][colNode];
-      if (matOp.assemble(asmMatrix))
+      if (matOp.doAssemble(asmMatrix))
         matOp.assembled = true;
 
       // finish boundary condition
diff --git a/src/amdis/ContextGeometry.hpp b/src/amdis/ContextGeometry.hpp
index d679715fe4ea90c48f418aa509b0ee0adf68143f..6307603e484c7d19668e360b1a659a6e3809cab0 100644
--- a/src/amdis/ContextGeometry.hpp
+++ b/src/amdis/ContextGeometry.hpp
@@ -1,65 +1,157 @@
 #pragma once
 
+#include <type_traits>
+
+#include <dune/common/typetraits.hh>
+#include <dune/common/std/optional.hh>
+#include <dune/geometry/type.hh>
+
 namespace AMDiS
 {
-  template <class LocalContext, class Geometry, class LocalGeometry>
+  namespace Impl
+  {
+    template <class E, class = Dune::void_t<>>
+    struct ContextTypes
+    {
+      using Entity = E;
+      using LocalGeometry = typename E::Geometry;
+    };
+
+    // specialization for intersections
+    template <class I>
+    struct ContextTypes<I, Dune::void_t<decltype(std::declval<I>().inside())>>
+    {
+      using Entity = typename I::Entity;
+      using LocalGeometry = typename I::LocalGeometry;
+    };
+
+  } // end namespace Impl
+
+
+  /// \brief Wrapper class for element and geometry
+  /**
+   * A LocalContext can be either a grid entity of codim 0 (called an element)
+   * or an intersection of elements. The element and its geometry may be stored
+   * externally and can be passed along with the localContext object.
+   * Since an intersection has a geometry (and localGeometry) different from the
+   * geometry (and localGeometry) of the entity it belongs to, these objects
+   * are provided as well.
+   **/
+  template <class LocalContextType>
   struct ContextGeometry
   {
+  public:
+
+    using LocalContext = LocalContextType;
+    using Element = typename Impl::ContextTypes<LocalContext>::Entity;
+    using Geometry = typename Element::Geometry;
+    using LocalGeometry = typename Impl::ContextTypes<LocalContext>::LocalGeometry;
+
+    using IsEntity = std::is_same<Element, LocalContext>;
+
     enum {
       dim = Geometry::mydimension,    //< the dimension of the grid element
       dow = Geometry::coorddimension  //< the dimension of the world
     };
 
-    LocalContext const& localContext;
-    Geometry const& geometry;
-    LocalGeometry const& localGeometry;
-
-    ContextGeometry(LocalContext const& localContext,
-                    Geometry const& geometry,
-                    LocalGeometry const& localGeometry)
-      : localContext(localContext)
-      , geometry(geometry)
-      , localGeometry(localGeometry)
+    /// Constructor. Stores pointer to localContext, element, and geometry.
+    ContextGeometry(LocalContext const& localContext, Element const& element, Geometry const& geometry)
+      : localContext_(&localContext)
+      , element_(&element)
+      , geometry_(&geometry)
     {}
 
-    /// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`.
-    template <class Coordinate>
-    decltype(auto) position(Coordinate const& p) const
+  public:
+
+    Element const& element() const
     {
-      return position(p, std::is_same<Geometry, LocalGeometry>{});
+      return *element_;
     }
 
-    /// The integration element from the `localGeometry`, the quadrature points are
-    /// defined in.
+    LocalContext const& localContext() const
+    {
+      return *localContext_;
+    }
+
+    Geometry const& geometry() const
+    {
+      return *geometry_;
+    }
+
+    LocalGeometry const& localGeometry() const
+    {
+      return localGeometryImpl(IsEntity{});
+    }
+
+
+  public:
+
+    /// Coordinate `p` given in `localGeometry`, transformed to coordinate in `geometry`.
     template <class Coordinate>
-    auto integrationElement(Coordinate const& p) const
+    decltype(auto) local(Coordinate const& p) const
     {
-      return localGeometry.integrationElement(p);
+      return localImpl(p, IsEntity{});
     }
 
     /// Transformation of coordinate `p` given in `localGeometry` to world space coordinates.
     template <class Coordinate>
     decltype(auto) global(Coordinate const& p) const
     {
-      return geometry.global(p);
+      return geometry_->global(p);
+    }
+
+    /// Return the geometry-type of the localContext
+    Dune::GeometryType type() const
+    {
+      return localContext_->type();
+    }
+
+    /// The integration element from the `localGeometry`, the quadrature points are
+    /// defined in.
+    template <class Coordinate>
+    auto integrationElement(Coordinate const& p) const
+    {
+      return localGeometry().integrationElement(p);
     }
 
   private: // implementation detail
 
     // position for elements
     template <class Coordinate>
-    Coordinate const& position(Coordinate const& p, std::true_type) const
+    Coordinate const& localImpl(Coordinate const& p, std::true_type) const
     {
       return p;
     }
 
     // position for intersection
     template <class Coordinate>
-    auto position(Coordinate const& p, std::false_type) const
+    auto localImpl(Coordinate const& p, std::false_type) const
+    {
+      return localGeometry().global(p);
+    }
+
+    // local-geometry is the same as geometry
+    Geometry const& localGeometryImpl(std::true_type) const
+    {
+      return *geometry_;
+    }
+
+    // local-geometry of intersection in inside element
+    LocalGeometry const& localGeometryImpl(std::false_type) const
     {
-      return localGeometry.global(p);
+      if (!localGeometry_)
+        localGeometry_.emplace(localContext_->geometryInInside());
+
+      return *localGeometry_;
     }
 
+  private:
+    LocalContext const* localContext_;
+    Element const* element_;
+    Geometry const* geometry_;
+
+    // The localGeometry may be constructed only if needed
+    mutable Dune::Std::optional<LocalGeometry> localGeometry_;
   };
 
 } // end namespace AMDiS
diff --git a/src/amdis/FiniteElementSpaces.hpp b/src/amdis/FiniteElementSpaces.hpp
deleted file mode 100644
index 10775960cc76104b8a24d2a8a217c52b4597f22e..0000000000000000000000000000000000000000
--- a/src/amdis/FiniteElementSpaces.hpp
+++ /dev/null
@@ -1,133 +0,0 @@
-#pragma once
-
-#include <amdis/common/TupleUtility.hpp>
-#include <amdis/common/IndexSeq.hpp>
-#include <amdis/common/Loops.hpp>
-
-namespace AMDiS
-{
-  template <class FeSpace>
-  struct LocalView
-  {
-    using type = typename FeSpace::LocalView;
-  };
-
-  template <class FeSpace>
-  struct LocalIndexSet
-  {
-    using type = typename FeSpace::LocalIndexSet;
-  };
-
-
-  template <class FeSpaces>
-  class FiniteElementSpaces
-  {
-    template <std::size_t I>
-    using FeSpace = std::tuple_element_t<I, FeSpaces>;
-
-    static constexpr int nComponents = std::tuple_size<FeSpaces>::value;
-
-    static_assert( nComponents > 0, "" );
-
-    using LocalViews = MapTuple_t<LocalView, FeSpaces>;
-    using LocalIndexSets = MapTuple_t<LocalIndexSet, FeSpaces>;
-
-    /// The grid view the global FE basis lives on
-    using GridView = typename FeSpace<0>::GridView;
-
-    /// Type of the grid element we are bound to
-    using Element = typename GridView::template Codim<0>::Entity;
-
-  public:
-    explicit FiniteElementSpaces(std::shared_ptr<FeSpaces> const& feSpaces)
-      : feSpaces_(feSpaces)
-      , localViews_(mapTuple([](auto const& basis) { return basis.localView(); }, *feSpaces))
-      , localIndexSets_(mapTuple([](auto const& basis) { return basis.localIndexSet(); }, *feSpaces))
-    {}
-
-    /// Update all global bases. This will update the indexing information of the global basis.
-    /// NOTE: It must be called if the grid has changed.
-    void update(GridView const& gv)
-    {
-      forEach(range_<0, nComponents>, [&,this](auto const _i)
-      {
-        static const int I = decltype(_i)::value;
-        std::get<I>(*feSpaces_).update(gv);
-      });
-    }
-
-    /// Bind the \ref localViews and \ref localIndexSets to a grid element
-    void bind(Element const& element)
-    {
-      forEach(range_<0, nComponents>, [&,this](auto const _i)
-      {
-        static const int I = decltype(_i)::value;
-
-        auto& localView = std::get<I>(localViews_);
-        localView.bind(element);
-
-        auto& localIndexSet = std::get<I>(localIndexSets_);
-        localIndexSet.bind(localView);
-      });
-      // NOTE: maybe create element-geometry here
-      bound_ = true;
-    }
-
-    /// Unbind from the current element
-    void unbind()
-    {
-      forEach(range_<0, nComponents>, [&,this](auto const _i)
-      {
-        static const int I = decltype(_i)::value;
-        std::get<I>(localIndexSets_).unbind();
-        std::get<I>(localViews_).unbind();
-      });
-      bound_ = false;
-    }
-
-    template <std::size_t I>
-    auto const& feSpace(const index_t<I> _i = {}) const
-    {
-      return std::get<I>(*feSpaces_);
-    }
-
-    template <std::size_t I>
-    auto const& localView(const index_t<I> _i = {}) const
-    {
-      assert( bound_ && "localViews must be bound to an element." );
-      return std::get<I>(localViews_);
-    }
-
-    template <std::size_t I>
-    auto const& localIndexSet(const index_t<I> _i = {}) const
-    {
-      assert( bound_ && "localIndexSets must be bound to a localView." );
-      return std::get<I>(localIndexSets_);
-    }
-
-    auto const& element() const
-    {
-      assert( bound_ && "localViews must be bound to an element." );
-      return std::get<0>(localViews_).element();
-    }
-
-    auto const& gridView() const
-    {
-      return std::get<0>(*feSpaces_).gridView();
-    }
-
-  private:
-    /// Tuple of global functionspace bases
-    std::shared_ptr<FeSpaces> feSpaces_;
-
-    /// Tuple of localView objects, obtained from the tuple of global bases
-    LocalViews localViews_;
-
-    /// Tuple of localIndexSet objects, obtained from the tuple of global bases
-    LocalIndexSets localIndexSets_;
-
-    /// True, if localViews and localIndexSets are bound to an element
-    bool bound_ = false;
-  };
-
-} // end namespace AMDiS
diff --git a/src/amdis/GridFunctionOperator.hpp b/src/amdis/GridFunctionOperator.hpp
index 9b828ff797e29843d5daa253c6e69464cc616bec..70a12642d81e1fd311b8957c6833bf0e751378f2 100644
--- a/src/amdis/GridFunctionOperator.hpp
+++ b/src/amdis/GridFunctionOperator.hpp
@@ -4,6 +4,8 @@
 #include <type_traits>
 
 #include <amdis/GridFunctions.hpp>
+#include <amdis/LocalOperator.hpp>
+#include <amdis/QuadratureFactory.hpp>
 #include <amdis/common/Utility.hpp>
 #include <amdis/utility/FiniteElementType.hpp>
 
@@ -14,7 +16,8 @@ namespace AMDiS
    * @{
    **/
 
-  /// \brief The main implementation of an operator to be used in a \ref LocalAssembler.
+  /// \brief The main implementation of an CRTP-base class for operators using a grid-function
+  /// coefficient to be used in a \ref LocalAssembler.
   /**
    * An Operator that takes a GridFunction as coefficient.
    * Provides quadrature rules and handles the evaluation of the GridFunction at
@@ -22,54 +25,58 @@ namespace AMDiS
    *
    * The class is specialized, by deriving from it, in \ref GridFunctionOperator.
    *
+   * \tparam Derived      The class derived from GridFunctionOperatorBase
+   * \tparam LocalContext The Element or Intersection type
    * \tparam GridFunction The GridFunction, a LocalFunction is created from, and
    *                      that is evaluated at quadrature points.
-   * \tparam QuadratureCreator A functor that provides a \ref Dune::QuadratureRule.
    *
    * **Requirements:**
+   * - `LocalContext` models either Entity (of codim 0) or Intersection
    * - `GridFunction` models the \ref Concepts::GridFunction
-   * - `QuadratureCreator` models \ref Concepts::Callable<Dune::GeometryType, LocalFunction, F>
-   *   where `F` is a functor of the signature `int(int)` that calculates the
-   *   degree of the (bi)linear-form. The argument passed to `F` is the polynomial
-   *   order of the GridFunction.
    **/
-  template <class GridFunction, class QuadratureCreator>
+  template <class Derived, class LocalContext, class GridFunction>
   class GridFunctionOperatorBase
+      : public LocalOperator<Derived, LocalContext>
   {
+    /// The type of the localFunction associated with the GridFunction
     using LocalFunction = decltype(localFunction(std::declval<GridFunction>()));
-    using Element = typename GridFunction::EntitySet::Element;
+
+    /// The Codim=0 entity of the grid, the localFunction can be bound to
+    using Element = typename Impl::ContextTypes<LocalContext>::Entity;
+    /// The geometry-type of the grid element
     using Geometry = typename Element::Geometry;
 
+    /// The type of the local coordinates in the \ref Element
     using LocalCoordinate = typename GridFunction::EntitySet::LocalCoordinate;
 
+    /// A factory for QuadratureRules that incooperate the order of the LocalFunction
+    using QuadFactory = QuadratureFactory<typename Geometry::ctype, LocalContext::mydimension, LocalFunction>;
+
   public:
-    /// \brief Constructor. Stores a copy of `expr`.
+    /// \brief Constructor. Stores a copy of `gridFct`.
     /**
-     * An expression operator takes an expression, following the interface of
-     * \ref ExpressionBase, and stores a copy. Additionally, it gets the
-     * differentiation order, to calculate the quadrature degree in \ref getDegree.
+     * A GridFunctionOperator takes a gridFunction and the
+     * differentiation order of the operator, to calculate the
+     * quadrature degree in \ref getDegree.
      **/
-    GridFunctionOperatorBase(GridFunction const& gridFct, QuadratureCreator creator, int order)
+    GridFunctionOperatorBase(GridFunction const& gridFct, int termOrder)
       : gridFct_(gridFct)
       , localFct_(localFunction(gridFct_))
-      , quadCreator_(creator)
-      , order_(order)
+      , termOrder_(termOrder)
     {}
 
     // Copy constructor
     GridFunctionOperatorBase(GridFunctionOperatorBase const& that)
       : gridFct_(that.gridFct_)
       , localFct_(localFunction(gridFct_)) // recreate localFct_ on new gridFct_
-      , quadCreator_(that.quadCreator_)
-      , order_(that.order_)
+      , termOrder_(that.termOrder_)
     {}
 
     // Move constructor
     GridFunctionOperatorBase(GridFunctionOperatorBase&& that)
       : gridFct_(std::move(that.gridFct_))
       , localFct_(localFunction(gridFct_)) // recreate localFct_ on new gridFct_
-      , quadCreator_(std::move(that.quadCreator_))
-      , order_(std::move(that.order_))
+      , termOrder_(std::move(that.termOrder_))
     {}
 
     /// \brief Binds operator to `element` and `geometry`.
@@ -78,328 +85,197 @@ namespace AMDiS
      * Since all operators need geometry information, the `Element::Geometry`
      * object `geometry` is created once, during grid traversal, and passed in.
      *
-     * By default, it binds the \ref localFct_ to the `element`.
+     * By default, it binds the \ref localFct_ to the `element` and the Quadrature
+     * factory to the localFunction.
      **/
-    void bind(Element const& element, Geometry const& geometry)
+    void bind_impl(Element const& element, Geometry const& geometry)
     {
-      if (!bound_) {
-        localFct_.bind(element);
-        isSimplex_ = geometry.type().isSimplex();
-        isAffine_ = geometry.affine();
-        bound_ = true;
-      }
+      assert( bool(quadFactory_) );
+      localFct_.bind(element);
+      quadFactory_->bind(localFct_);
     }
 
     /// Unbinds operator from element.
-    void unbind()
+    void unbind_impl()
     {
-      bound_ = false;
       localFct_.unbind();
     }
 
+    /// Create a quadrature factory from a PreQuadratureFactory, e.g. class derived from \ref QuadratureFactory
+    template <class PreQuadFactory>
+    void setQuadFactory(PreQuadFactory const& pre)
+    {
+      quadFactory_ = makeQuadratureFactoryPtr<typename Geometry::ctype, LocalContext::mydimension, LocalFunction>(pre);
+    }
+
+  protected:
     /// Return expression value at LocalCoordinates
     auto coefficient(LocalCoordinate const& local) const
     {
-      assert( bound_ );
+      assert( this->bound_ );
       return localFct_(local);
     }
 
-
-    /// Create a quadrature rule using the \ref QuadratureCreator by calculating the
+    /// Create a quadrature rule using the \ref QuadratureFactory by calculating the
     /// quadrature order necessary to integrate the (bi)linear-form accurately.
     template <class... Nodes>
-    decltype(auto) getQuadratureRule(Dune::GeometryType type, Nodes const&... nodes) const
-    {
-      auto degreeFunctor = [&,this](int order) -> int { return this->getDegree(order, nodes...); };
-      return quadCreator_(type, localFct_, degreeFunctor);
-    }
-
-  protected:
-    /// \brief Return the quadrature degree for a vector operator.
-    /**
-     * The quadrature degree that is necessary, to integrate the expression
-     * multiplied with (possibly derivatives of) shape functions. Thus it needs
-     * the order of derivatives, this operator implements.
-     **/
-    template <class Node>
-    int getDegree(int coeffDegree, Node const& node) const
-    {
-      assert( bound_ );
-
-      int psiDegree = polynomialDegree(node);
-
-      int degree = psiDegree + coeffDegree;
-      if (isSimplex_)
-        degree -= order_;
-      if (isAffine_)
-        degree += 1; // oder += (order+1)
-
-      return degree;
-    }
-
-
-    /// \brief Return the quadrature degree for a matrix operator.
-    /**
-     * The quadrature degree that is necessary, to integrate the expression
-     * multiplied with (possibly derivatives of) shape functions. Thus it needs
-     * the order of derivatives, this operator implements.
-     **/
-    template <class RowNode, class ColNode>
-    int getDegree(int coeffDegree, RowNode const& rowNode, ColNode const& colNode) const
+    auto const& getQuadratureRule(Dune::GeometryType type, Nodes const&... nodes) const
     {
-      assert( bound_ );
-
-      int psiDegree = polynomialDegree(rowNode);
-      int phiDegree = polynomialDegree(colNode);
-
-      int degree = psiDegree + phiDegree + coeffDegree;
-      if (isSimplex_)
-        degree -= order_;
-      if (isAffine_)
-        degree += 1; // oder += (order+1)
-
-      return degree;
+      assert( bool(quadFactory_) );
+      int quadDegree = this->getDegree(termOrder_, quadFactory_->order(), nodes...);
+      return quadFactory_->rule(type, quadDegree);
     }
 
   private:
+    /// The gridFunction to be used within the operator
     GridFunction gridFct_;
+
+    /// localFunction associated with gridFunction. Mus be updated whenever gridFunction changes.
     LocalFunction localFct_;
 
-    QuadratureCreator quadCreator_; //< a creator to provide a quadrature rule
-    int order_;                     //< the derivative order of this operator
+    /// Assign each element type a quadrature rule
+    std::shared_ptr<QuadFactory> quadFactory_ = std::make_shared<QuadFactory>();
 
-    bool isSimplex_ = false;    //< the bound element is a simplex
-    bool isAffine_ = false;     //< the bound geometry is affine
-    bool bound_ = false;        //< an element is bound to the operator
+    /// the derivative order of this operator (in {0, 1, 2})
+    int termOrder_ = 0;
   };
 
 
-  /// A default implementation of an GridFunctionOperator if no specialization is available.
-  /**
-   * An operator must implement either \ref calculateElementVector, or
-   * \ref calculateElementMatrix, if it is a vector or matrix operator,
-   * respectively.
-   **/
-  template <class Tag, class GridFct, class QuadratureCreator>
-  class GridFunctionOperator
-      : public GridFunctionOperatorBase<GridFct, QuadratureCreator>
+  /// \brief The transposed operator, implemented in term of its transposed by
+  /// calling \ref getElementMatrix with inverted arguments.
+  template <class Derived, class Transposed>
+  class GridFunctionOperatorTransposed
+      : public LocalOperator<Derived, typename Transposed::LocalContext>
   {
+    template <class T, class... Args>
+    using Constructable = decltype( new T(std::declval<Args>()...) );
+
   public:
-    GridFunctionOperator(Tag, GridFct const& gridFct, QuadratureCreator const& quadCreator)
-      : GridFunctionOperatorBase<GridFct, QuadratureCreator>(gridFct, 0, quadCreator)
+    template <class... Args,
+      std::enable_if_t<Dune::Std::is_detected<Constructable, Transposed, Args...>::value, int> = 0>
+    GridFunctionOperatorTransposed(Args&&... args)
+      : transposedOp_(std::forward<Args>(args)...)
     {}
 
-    /// \brief Assemble a local element vector on the element that is bound.
-    /**
-     * \param contextGeometry Container for context related data
-     * \param quad A quadrature formula
-     * \param elementVector The output element vector
-     * \param node The node of the test-basis
-     **/
-    template <class Context, class QuadratureRule,
-              class ElementVector, class Node>
-    void calculateElementVector(Context const& contextGeometry,
-                                QuadratureRule const& quad,
-                                ElementVector& elementVector,
-                                Node const& node)
+    /// Redirects the bind call top the transposed operator
+    template <class Element, class Geometry>
+    void bind_impl(Element const& element, Geometry const& geometry)
     {
-      error_exit("Needs to be implemented!");
+      transposedOp_.bind_impl(element, geometry);
     }
 
-    /// \brief Assemble a local element matrix on the element that is bound.
-    /**
-     * \param contextGeometry Container for context related data
-     * \param quad A quadrature formula
-     * \param elementMatrix The output element matrix
-     * \param rowNode The node of the test-basis
-     * \param colNode The node of the trial-basis
-     * \param flag1 finiteelement is the same for test and trial
-     * \param flag2 nodes are the same in the basis-tree
-     **/
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& contextGeometry,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flag1,
-                                std::integral_constant<bool, sameNode> flag2)
+    /// Redirects the unbind call top the transposed operator
+    void unbind_impl()
     {
-      error_exit("Needs to be implemented!");
+      transposedOp_.unbind_impl();
     }
-  };
-
 
-#ifndef DOXYGEN
-  namespace Concepts
-  {
-    namespace Definition
+    /// Redirects the setQuadFactory call top the transposed operator
+    template <class PreQuadFactory>
+    void setQuadFactory(PreQuadFactory const& pre)
     {
-      struct HasGridFunctionOrder
-      {
-        template <class F, class GridView>
-        auto requires_(F&& f, GridView const& gridView)
-          -> decltype( order(localFunction(makeGridFunction(f, gridView))) );
-      };
+      transposedOp_.setQuadFactory(pre);
     }
 
-    template <class F, class GridView = Dune::YaspGrid<2>::LeafGridView>
-    constexpr bool HasGridFunctionOrder = models<Definition::HasGridFunctionOrder(F, GridView)>;
-
-  } // end namespace Concepts
-
-
-  namespace tag
-  {
-    struct deduce {};
-    struct order {};
-    struct rule {};
-
-  } // end namespace tag
-
-
-  template <class Tag, class Expr, class QuadTag, class Rule = void>
-  struct ExpressionPreOperator;
-
-  template <class Tag, class Expr>
-  struct ExpressionPreOperator<Tag, Expr, tag::deduce>
-  {
-    Tag tag;
-    Expr expr;
-  };
+    /// Apply the assembling to the transposed elementMatrix with interchanged row-/colNode
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
+    {
+      auto elementMatrixTransposed = trans(elementMatrix);
+      transposedOp_.getElementMatrix(
+        context, colNode, rowNode, elementMatrixTransposed);
+    }
 
-  template <class Tag, class Expr>
-  struct ExpressionPreOperator<Tag, Expr, tag::order>
-  {
-    Tag tag;
-    Expr expr;
-    int order;
-    Dune::QuadratureType::Enum qt;
+  private:
+    Transposed transposedOp_;
   };
 
-  template <class Tag, class Expr, class Rule>
-  struct ExpressionPreOperator<Tag, Expr, tag::rule, Rule>
+  template <class Tag, class PreGridFct, class PreQuadFactory>
+  struct PreGridFunctionOperator
   {
     Tag tag;
-    Expr expr;
-    Rule const& rule;
+    PreGridFct expr;
+    PreQuadFactory quadFactory;
   };
-#endif
-
 
   /// Store tag and expression to create a \ref GridFunctionOperator
-  template <class Tag, class Expr>
-  auto makeOperator(Tag tag, Expr const& expr)
-  {
-    using RawExpr = Underlying_t<Expr>;
-    static_assert(Concepts::HasGridFunctionOrder<RawExpr>,
-      "Polynomial degree of expression can not be deduced. You need to provide a polynomial order or a quadrature rule in 'makeOperator()'.");
-
-    return Dune::Hybrid::ifElse(bool_<Concepts::HasGridFunctionOrder<RawExpr>>,
-      [&](auto) { return ExpressionPreOperator<Tag, Expr, tag::deduce>{tag, expr}; },
-      [&](auto) { return ExpressionPreOperator<Tag, double, tag::deduce>{tag, 0.0}; });
-  }
-
-  /// Store tag and expression and polynomial order of expression to create a \ref GridFunctionOperator
-  template <class Tag, class Expr>
-  auto makeOperator(Tag tag, Expr const& expr, int order,
-                    Dune::QuadratureType::Enum qt = Dune::QuadratureType::GaussLegendre)
-  {
-    return ExpressionPreOperator<Tag, Expr, tag::order>{tag, expr, order, qt};
-  }
-
-  /// Store tag and expression and a quadrature rule to create a \ref GridFunctionOperator
-  template <class Tag, class Expr, class ctype, int dim>
-  auto makeOperator(Tag tag, Expr const& expr, Dune::QuadratureRule<ctype,dim> const& rule)
+  template <class Tag, class PreGridFct, class... QuadratureArgs>
+  auto makeOperator(Tag tag, PreGridFct const& expr, QuadratureArgs&&... args)
   {
-    return ExpressionPreOperator<Tag, Expr, tag::rule, Dune::QuadratureRule<ctype,dim>>{tag, expr, rule};
+    auto preQuadFactory = makePreQuadratureFactory(std::forward<QuadratureArgs>(args)...);
+    return PreGridFunctionOperator<Tag, PreGridFct, decltype(preQuadFactory)>{tag, expr, preQuadFactory};
   }
 
   /** @} **/
 
 #ifndef DOXYGEN
 
-  namespace Impl
-  {
-    // Deduce polynomial order of expression automatically. Create standard quadrature rule with degree
-    // build up of operator derivative order, and polynomial degrees of trial/test functions.
-    template <class Tag, class Expr, class GridView>
-    auto makeQuadCreator(ExpressionPreOperator<Tag, Expr, tag::deduce> const& /*op*/, GridView const& /*gridView*/)
-    {
-      using QuadratureRules = Dune::QuadratureRules<typename GridView::ctype, GridView::dimension>;
-      return [](auto type, auto&& localFct, auto getDegree) -> auto const&
-      {
-        return QuadratureRules::rule(type, getDegree(order(localFct)));
-      };
-    }
-
-    // Provide polynomial order of expression explicitly
-    template <class Tag, class Expr, class GridView>
-    auto makeQuadCreator(ExpressionPreOperator<Tag, Expr, tag::order> const& op, GridView const& /*gridView*/)
-    {
-      using QuadratureRules = Dune::QuadratureRules<typename GridView::ctype, GridView::dimension>;
-      return [order=op.order,qt=op.qt](auto type, auto&& /*localFct*/, auto getDegree) -> auto const&
-      {
-        return QuadratureRules::rule(type, getDegree(order), qt);
-      };
-    }
-
-    // Provide quadrature rule explicitly
-    template <class Tag, class Expr, class Rule, class GridView>
-    auto makeQuadCreator(ExpressionPreOperator<Tag, Expr, tag::rule, Rule> const& op, GridView const& /*gridView*/)
-    {
-      return [&rule=op.rule](auto&&...) -> auto const&
-      {
-        return rule;
-      };
-    }
-
-  } // end namespace Impl
+  /// The base-template for GridFunctionOperators
+  /**
+   * An operator can specialize this class, by deriving from \ref GridFunctionOperatorBase.
+   * With the generic function \ref makeLocalOperator, an instance is created. To
+   * distinguisch different GridFunction operators, a tag can be provided that has no
+   * other effect.
+   *
+   * \tparam Tag  An Identifier for this GridFunctionOperator
+   * \tparam LocalContext  An Element or Intersection the operator is evaluated on
+   * \tparam GridFct  A GridFunction evaluated in local coordinates on the bound element
+   **/
+  template <class Tag, class LocalContext, class GridFct>
+  class GridFunctionOperator
+      : public GridFunctionOperatorBase<GridFunctionOperator<Tag, LocalContext, GridFct>, LocalContext, GridFct>
+  {};
 
 
   /// Generate an \ref GridFunctionOperator from a PreOperator (tag, expr).
   /// @{
-  template <class Tag, class... Args, class GridView>
-  auto makeGridOperator(ExpressionPreOperator<Tag, Args...> const& op, GridView const& gridView)
+  template <class LocalContext, class Tag, class... Args, class GridView>
+  auto makeLocalOperator(PreGridFunctionOperator<Tag, Args...> const& op, GridView const& gridView)
   {
     auto gridFct = makeGridFunction(op.expr, gridView);
-    auto quadCreator = Impl::makeQuadCreator(op, gridView);
-    using GridFctOp = GridFunctionOperator<Tag, decltype(gridFct), decltype(quadCreator)>;
-    return GridFctOp{op.tag, gridFct, quadCreator};
+    using GridFctOp = GridFunctionOperator<Tag, LocalContext, decltype(gridFct)>;
+    GridFctOp localOperator{op.tag, gridFct};
+    localOperator.setQuadFactory(op.quadFactory);
+    return localOperator;
   }
 
-  template <class Tag, class... Args, class GridView>
-  auto makeGridOperator(std::reference_wrapper<ExpressionPreOperator<Tag, Args...>> op, GridView const& gridView)
+  template <class LocalContext, class Tag, class... Args, class GridView>
+  auto makeLocalOperator(std::reference_wrapper<PreGridFunctionOperator<Tag, Args...>> op, GridView const& gridView)
   {
-    ExpressionPreOperator<Tag, Args...> const& op_ref = op;
+    PreGridFunctionOperator<Tag, Args...> const& op_ref = op;
     auto gridFct = makeGridFunction(std::ref(op_ref.expr), gridView);
-    auto quadCreator = Impl::makeQuadCreator(op_ref, gridView);
-    using GridFctOp = GridFunctionOperator<Tag, decltype(gridFct), decltype(quadCreator)>;
-    return GridFctOp{op_ref.tag, gridFct, quadCreator};
+    using GridFctOp = GridFunctionOperator<Tag, LocalContext, decltype(gridFct)>;
+    GridFctOp localOperator{op_ref.tag, gridFct};
+    localOperator.setQuadFactory(op_ref.quadFactory);
+    return localOperator;
   }
   /// @}
 
 
   /// Generate a shared_ptr to \ref GridFunctionOperator from a PreOperator (tag, expr).
   /// @{
-  template <class Tag, class... Args, class GridView>
-  auto makeGridOperatorPtr(ExpressionPreOperator<Tag, Args...> const& op, GridView const& gridView)
+  template <class LocalContext, class Tag, class... Args, class GridView>
+  auto makeLocalOperatorPtr(PreGridFunctionOperator<Tag, Args...> const& op, GridView const& gridView)
   {
     auto gridFct = makeGridFunction(op.expr, gridView);
-    auto quadCreator = Impl::makeQuadCreator(op, gridView);
-    using GridFctOp = GridFunctionOperator<Tag, decltype(gridFct), decltype(quadCreator)>;
-    return std::make_shared<GridFctOp>(op.tag, gridFct, quadCreator);
+    using GridFctOp = GridFunctionOperator<Tag, LocalContext, decltype(gridFct)>;
+    auto localOperator = std::make_shared<GridFctOp>(op.tag, gridFct);
+    localOperator->setQuadFactory(op.quadFactory);
+    return localOperator;
   }
 
-  template <class Tag, class... Args, class GridView>
-  auto makeGridOperatorPtr(std::reference_wrapper<ExpressionPreOperator<Tag, Args...>> op, GridView const& gridView)
+  template <class LocalContext, class Tag, class... Args, class GridView>
+  auto makeLocalOperatorPtr(std::reference_wrapper<PreGridFunctionOperator<Tag, Args...>> op, GridView const& gridView)
   {
-    ExpressionPreOperator<Tag, Args...> const& op_ref = op;
+    PreGridFunctionOperator<Tag, Args...> const& op_ref = op;
     auto gridFct = makeGridFunction(std::ref(op_ref.expr), gridView);
-    auto quadCreator = Impl::makeQuadCreator(op_ref, gridView);
-    using GridFctOp = GridFunctionOperator<Tag, decltype(gridFct), decltype(quadCreator)>;
-    return std::make_shared<GridFctOp>(op_ref.tag, gridFct, quadCreator);
+    using GridFctOp = GridFunctionOperator<Tag, LocalContext, decltype(gridFct)>;
+    auto localOperator = std::make_shared<GridFctOp>(op_ref.tag, gridFct);
+    localOperator->setQuadFactory(op_ref.quadFactory);
+    return localOperator;
   }
   /// @}
 
diff --git a/src/amdis/LocalAssembler.hpp b/src/amdis/LocalAssembler.hpp
index 424cc4560b42df6a9a4e98f5dc69757fbb0ea4ef..1d47532dfd273c401c1c5182483ba0e19ecf9ba2 100644
--- a/src/amdis/LocalAssembler.hpp
+++ b/src/amdis/LocalAssembler.hpp
@@ -23,12 +23,8 @@ namespace AMDiS
   private:
 
     using Element = typename Super::Element;
-    using ElementMatrixVector = typename Super::ElementMatrixVector;
-
     using Geometry = typename Super::Geometry;
-    using LocalGeometry = typename Super::LocalGeometry;
-
-    using Context = ContextGeometry<LocalContext, Geometry, LocalGeometry>;
+    using ElementMatrixVector = typename Super::ElementMatrixVector;
 
   public:
 
@@ -69,26 +65,16 @@ namespace AMDiS
 
     /// Implementation of \ref LocalAssemblerBase::assemble
     /**
-     * Provides a quadrature formula with necessary degree to integrate the operator,
-     * stores geometry and localGeometry and a \ref ContextGeometry and calls
+     * Stores geometry and localGeometry and calls
      * \ref calculateElementVector or \ref calculateElementMatrix on the
      * vector or matrix operator, respectively.
-     *
-     * The call to operator passes two optimization flags:
-     * 1. RowNode and ColNode implement the same local finiteelement
-     * 2. RowNode and ColNode are the same node in the globalBasis tree.
      **/
-    virtual bool assemble(
-        LocalContext const& localContext,
-        ElementMatrixVector& elementMatrixVector,
-        Nodes const&... nodes) final
+    virtual void assemble(LocalContext const& localContext,
+                          Nodes const&... nodes,
+                          ElementMatrixVector& elementMatrixVector) final
     {
-      auto&& localGeometry = getLocalGeometry(localContext);
-      auto&& quad = op_.getQuadratureRule(localGeometry.type(), nodes...);
-
-      Context data{localContext, getGeometry(), localGeometry};
-      assembleImpl(data, std::forward<decltype(quad)>(quad), elementMatrixVector, nodes...);
-      return true;
+      ContextGeometry<LocalContext> context{localContext, getElement(), getGeometry()};
+      assembleImpl(context, nodes..., elementMatrixVector);
     }
 
 
@@ -97,96 +83,46 @@ namespace AMDiS
   protected: // implementation detail
 
     // matrix assembling
-    template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
-    void assembleImpl(Context const& context,
-                      QuadratureRule const& quad,
-                      ElementMatrix& elementMatrix,
-                      RowNode const& rowNode, ColNode const& colNode)
-    {
-      assembleImpl(context, quad, elementMatrix, rowNode, colNode,
-        std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>{});
-    }
-
-    // local finite elements are the same for rowNode and colNode
-    template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
-    void assembleImpl(Context const& context,
-                      QuadratureRule const& quad,
-                      ElementMatrix& elementMatrix,
-                      RowNode const& rowNode, ColNode const& colNode,
-                      std::true_type /*sameFE*/)
-    {
-      if (rowNode.treeIndex() == colNode.treeIndex())
-        op_.calculateElementMatrix(
-          context, quad, elementMatrix, rowNode, colNode, std::true_type{}, std::true_type{});
-      else
-        op_.calculateElementMatrix(
-          context, quad, elementMatrix, rowNode, colNode, std::true_type{}, std::false_type{});
-    }
-
-    // local finite elements are different for rowNode and colNode
-    template <class QuadratureRule, class ElementMatrix, class RowNode, class ColNode>
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
     void assembleImpl(Context const& context,
-                      QuadratureRule const& quad,
-                      ElementMatrix& elementMatrix,
                       RowNode const& rowNode, ColNode const& colNode,
-                      std::false_type /*sameFE*/)
+                      ElementMatrix& elementMatrix)
     {
-      op_.calculateElementMatrix(
-        context, quad, elementMatrix, rowNode, colNode, std::false_type{}, std::false_type{});
+      op_.calculateElementMatrix(context, rowNode, colNode, elementMatrix);
     }
 
-
     // vector assembling
-    template <class QuadratureRule, class ElementVector, class Node>
+    template <class Context, class Node, class ElementVector>
     void assembleImpl(Context const& context,
-                      QuadratureRule const& quad,
-                      ElementVector& elementVector,
-                      Node const& node)
+                      Node const& node,
+                      ElementVector& elementVector)
     {
-      op_.calculateElementVector(context, quad, elementVector, node);
+      op_.calculateElementVector(context, node, elementVector);
     }
 
 #endif // DOXYGEN
 
-
   public:
 
+    /// return the bound entity (of codim 0)
     Element const& getElement() const
     {
       assert( element_ );
       return *element_;
     }
 
+    /// return the geometry of the bound element
     Geometry const& getGeometry() const
     {
       assert( geometry_ );
       return *geometry_;
     }
 
-    decltype(auto) getLocalGeometry(LocalContext const& context) const
-    {
-      return getLocalGeometry(context, std::is_same<LocalContext, Element>{});
-    }
-
-
-  private: // implementation detail
-
-    // localGeometry for Entities
-    Geometry const& getLocalGeometry(Element const& element, std::true_type) const
-    {
-      return *geometry_;
-    }
-
-    // localGeometry for intersections
-    LocalGeometry getLocalGeometry(LocalContext const& intersection, std::false_type) const
-    {
-      return intersection.geometryInInside();
-    }
-
 
   private:
 
-    std::unique_ptr<Operator> storage_;     //< the stored operator, implementing \ref GridFunctionOperatorBase
+    /// the stored operator, implementing \ref GridFunctionOperatorBase
+    std::unique_ptr<Operator> storage_;
     Operator& op_;
 
     Element const* element_ = nullptr;
diff --git a/src/amdis/LocalAssemblerBase.hpp b/src/amdis/LocalAssemblerBase.hpp
index 8ea0af9b1dc1d9bb082d0cd199d4b7d7a9d628c9..f6320729f7ddfc14d37557fa8635e03908948379 100644
--- a/src/amdis/LocalAssemblerBase.hpp
+++ b/src/amdis/LocalAssemblerBase.hpp
@@ -1,135 +1,46 @@
 #pragma once
 
-#include <list>
-#include <memory>
 #include <type_traits>
 
-#include <amdis/common/ConceptsBase.hpp>
+#include <amdis/ContextGeometry.hpp>
+// #include <amdis/common/ConceptsBase.hpp>
 #include <amdis/common/TypeDefs.hpp>
-#include <amdis/utility/TreeData.hpp>
 
 namespace AMDiS
 {
-  namespace Impl
-  {
-    template <class E, class = Void_t<>>
-    struct ContextImpl
-    {
-      using Entity = E;
-      using Geometry = typename E::Geometry;
-    };
-
-    // specialization for intersections
-    template <class I>
-    struct ContextImpl<I, Void_t<decltype(std::declval<I>().inside())>>
-    {
-      using Entity = typename I::Entity;
-      using Geometry = typename I::LocalGeometry;
-    };
-
-  } // end namespace Impl
-
-
   /// Abstract base-class of a \ref LocalAssembler
   template <class LocalContext, class... Nodes>
   class LocalAssemblerBase
   {
   public:
-
-    using Element = typename Impl::ContextImpl<LocalContext>::Entity;
+    /// The codim=0 grid entity
+    using Element = typename Impl::ContextTypes<LocalContext>::Entity;
+    /// The geometry of the \ref Element
     using Geometry = typename Element::Geometry;
-    using LocalGeometry = typename Impl::ContextImpl<LocalContext>::Geometry;
 
     static constexpr int numNodes = sizeof...(Nodes);
     static_assert( numNodes == 1 || numNodes == 2,
       "VectorAssembler gets 1 Node, MatrixAssembler gets 2 Nodes!");
 
+    /// Either an ElementVector or an ElementMatrix (depending on the number of nodes)
     using ElementMatrixVector = std::conditional_t<
       (sizeof...(Nodes)==1), Impl::ElementVector, std::conditional_t<
       (sizeof...(Nodes)==2), Impl::ElementMatrix, void>>;
 
-
   public:
-
+    /// Virtual destructor
     virtual ~LocalAssemblerBase() {}
 
+    /// Bind the local-assembler to the grid-element with its corresponding geometry
     virtual void bind(Element const& element, Geometry const& geometry) = 0;
+
+    /// Unbind from the element
     virtual void unbind() = 0;
 
     /// Assemble an element matrix or element vector on the test- (and trial-) function node(s)
-    virtual bool assemble(LocalContext const& localContext,
-                          ElementMatrixVector& elementMatrixVector,
-                          Nodes const&... nodes) = 0;
-  };
-
-
-  template <class GridView>
-  class OperatorLists
-  {
-    using Element = typename GridView::template Codim<0>::Entity;
-
-    template <class OperatorType>
-    struct Scaled
-    {
-      std::shared_ptr<OperatorType> op;
-      double* factor = nullptr;
-      double* estFactor = nullptr;
-      BoundaryType b = {0};
-    };
-
-    template <class... Nodes>
-    struct Data
-    {
-      using ElementOperator = LocalAssemblerBase<Element, Nodes...>;
-      using IntersectionOperator = LocalAssemblerBase<typename GridView::Intersection, Nodes...>;
-
-      std::list<Scaled<ElementOperator>> element;
-      std::list<Scaled<IntersectionOperator>> boundary;
-      std::list<Scaled<IntersectionOperator>> intersection;
-
-      bool assembled = false; // if false, do reassemble
-      bool changing = false; // if true, or assembled false, do reassemble
-
-      bool empty() const
-      {
-        return element.empty() && boundary.empty() && intersection.empty();
-      }
-
-      bool assemble(bool flag) const
-      {
-        return flag && (!assembled || changing);
-      }
-
-      template <class Geo>
-      void bind(Element const& elem, Geo const& geo)
-      {
-        for (auto& scaled : element) scaled.op->bind(elem,geo);
-        for (auto& scaled : boundary) scaled.op->bind(elem,geo);
-        for (auto& scaled : intersection) scaled.op->bind(elem,geo);
-      }
-
-      void unbind()
-      {
-        for (auto& scaled : element) scaled.op->unbind();
-        for (auto& scaled : boundary) scaled.op->unbind();
-        for (auto& scaled : intersection) scaled.op->unbind();
-      }
-    };
-
-  public:
-
-    template <class RowNode, class ColNode>
-    using MatData = Data<RowNode, ColNode>;
-
-    template <class Node>
-    using VecData = Data<Node>;
+    virtual void assemble(LocalContext const& localContext,
+                          Nodes const&... nodes,
+                          ElementMatrixVector& elementMatrixVector) = 0;
   };
 
-
-  template <class GlobalBasis>
-  using MatrixOperators = MatrixData<GlobalBasis, OperatorLists<typename GlobalBasis::GridView>::template MatData>;
-
-  template <class GlobalBasis>
-  using VectorOperators = VectorData<GlobalBasis, OperatorLists<typename GlobalBasis::GridView>::template VecData>;
-
 } // end namespace AMDiS
diff --git a/src/amdis/LocalAssemblerList.hpp b/src/amdis/LocalAssemblerList.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e4b1dc796a40c0fb90a6aaea7f48160a599de73c
--- /dev/null
+++ b/src/amdis/LocalAssemblerList.hpp
@@ -0,0 +1,96 @@
+#pragma once
+
+#include <list>
+#include <memory>
+
+#include <amdis/LocalAssemblerBase.hpp>
+#include <amdis/utility/TreeData.hpp>
+
+namespace AMDiS
+{
+  template <class GridView>
+  class OperatorLists
+  {
+    using Element = typename GridView::template Codim<0>::Entity;
+    using Intersection = typename GridView::Intersection;
+
+    template <class OperatorType>
+    struct DataElement
+    {
+      std::shared_ptr<OperatorType> op;
+      double* factor = nullptr;
+      double* estFactor = nullptr;
+      BoundaryType b = {0};
+    };
+
+    /// Lists of \ref DataElement on the Element, BoundaryIntersction, and InteriorIntersections
+    template <class... Nodes>
+    struct Data
+    {
+      /// The type of local operators associated with grid elements
+      using ElementOperator = LocalAssemblerBase<Element, Nodes...>;
+      /// The type of local operators associated with grid intersections
+      using IntersectionOperator = LocalAssemblerBase<Intersection, Nodes...>;
+
+      /// Return whether any operators are stored on the node
+      bool empty() const
+      {
+        return element.empty() && boundary.empty() && intersection.empty();
+      }
+
+      /// Test whether to assemble on the node
+      bool doAssemble(bool flag) const
+      {
+        return flag && (!assembled || changing);
+      }
+
+      /// Bind all operators to the grid element and geometry
+      template <class Geo>
+      void bind(Element const& elem, Geo const& geo)
+      {
+        for (auto& scaled : element) scaled.op->bind(elem,geo);
+        for (auto& scaled : boundary) scaled.op->bind(elem,geo);
+        for (auto& scaled : intersection) scaled.op->bind(elem,geo);
+      }
+
+      /// Unbind all operators from the element
+      void unbind()
+      {
+        for (auto& scaled : element) scaled.op->unbind();
+        for (auto& scaled : boundary) scaled.op->unbind();
+        for (auto& scaled : intersection) scaled.op->unbind();
+      }
+
+      /// List of operators to be assembled on grid elements
+      std::list<DataElement<ElementOperator>> element;
+      /// List of operators to be assembled on boundary intersections
+      std::list<DataElement<IntersectionOperator>> boundary;
+      /// List of operators to be assembled on interior intersections
+      std::list<DataElement<IntersectionOperator>> intersection;
+
+      /// if false, do reassemble of all operators
+      bool assembled = false;
+
+      /// if true, or \ref assembled false, do reassemble of all operators
+      bool changing = false;
+    };
+
+  public:
+
+    /// List of operators associated with matrix blocks (RowNode, ColNode)
+    template <class RowNode, class ColNode>
+    using MatData = Data<RowNode, ColNode>;
+
+    /// List of operators associated with vector blocks [Node]
+    template <class Node>
+    using VecData = Data<Node>;
+  };
+
+
+  template <class GlobalBasis>
+  using MatrixOperators = MatrixData<GlobalBasis, OperatorLists<typename GlobalBasis::GridView>::template MatData>;
+
+  template <class GlobalBasis>
+  using VectorOperators = VectorData<GlobalBasis, OperatorLists<typename GlobalBasis::GridView>::template VecData>;
+
+} // end namespace AMDiS
diff --git a/src/amdis/LocalOperator.hpp b/src/amdis/LocalOperator.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5509510a9ce52afe2312f8765993c6d2d8276600
--- /dev/null
+++ b/src/amdis/LocalOperator.hpp
@@ -0,0 +1,206 @@
+#pragma once
+
+#include <cassert>
+#include <type_traits>
+
+#include <amdis/GridFunctions.hpp>
+#include <amdis/common/Utility.hpp>
+#include <amdis/utility/FiniteElementType.hpp>
+
+namespace AMDiS
+{
+  /**
+   * \addtogroup operators
+   * @{
+   **/
+
+  /// \brief The main implementation of an operator to be used in a \ref LocalAssembler.
+  /**
+   * The CRTP Base class for local operators.
+   *
+   * \tparam Derived           The class that derives from this base class
+   * \tparam LocalContextType  The type of the element or intersection the operator is evaluated on
+   **/
+  template <class Derived, class LocalContextType>
+  class LocalOperator
+  {
+  public:
+    /// The element or intersection the operator is assembled on
+    using LocalContext = LocalContextType;
+    /// The codim=0 grid entity
+    using Element = typename Impl::ContextTypes<LocalContext>::Entity;
+    /// The geometry of the \ref Element
+    using Geometry = typename Element::Geometry;
+
+    /// Initialize the local operator on the current gridView
+    template <class GridView>
+    void init(GridView const& gridView)
+    {
+      derived().init_impl(gridView);
+    }
+
+    /// \brief Binds operator to `element` and `geometry`.
+    /**
+     * Binding an operator to the currently visited element in grid traversal.
+     * Since all operators need geometry information, the `Element::Geometry`
+     * object `geometry` is created once, during grid traversal, and passed in.
+     *
+     * By default, it binds the \ref localFct_ to the `element`.
+     **/
+    void bind(Element const& element, Geometry const& geometry)
+    {
+      if (!bound_) {
+        isSimplex_ = geometry.type().isSimplex();
+        isAffine_ = geometry.affine();
+        bound_ = true;
+      }
+
+      derived().bind_impl(element, geometry);
+    }
+
+    /// Unbinds operator from element.
+    void unbind()
+    {
+      derived().unbind_impl();
+      bound_ = false;
+    }
+
+    /// \brief Assemble a local element matrix on the element that is bound.
+    /**
+     * \param context Container for geometry related data, \ref ContextGeometry
+     * \param rowNode The node of the test-basis
+     * \param colNode The node of the trial-basis
+     * \param elementMatrix The output element matrix
+     **/
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void calculateElementMatrix(Context const& context,
+                                RowNode const& rowNode,
+                                ColNode const& colNode,
+                                ElementMatrix& elementMatrix)
+    {
+      derived().getElementMatrix(context, rowNode, colNode, elementMatrix);
+    }
+
+    /// \brief Assemble a local element vector on the element that is bound.
+    /**
+     * \param context Container for geometry related data \ref ContextGeometry
+     * \param node The node of the test-basis
+     * \param elementVector The output element vector
+     **/
+    template <class Context, class Node, class ElementVector>
+    void calculateElementVector(Context const& context,
+                                Node const& node,
+                                ElementVector& elementVector)
+    {
+      derived().getElementVector(context, node, elementVector);
+    }
+
+
+    Derived      & derived()       { return static_cast<Derived&>(*this); }
+    Derived const& derived() const { return static_cast<Derived const&>(*this); }
+
+
+  protected:
+
+    // default implementation. Can be overridden in the derived classes
+    template <class GridView>
+    void init_impl(GridView const& /*gridView*/) {}
+
+    // default implementation. Can be overridden in the derived classes
+    template <class Element, class Geometry>
+    void bind_impl(Element const& /*element*/, Geometry const& /*geometry*/) {}
+
+    // default implementation. Can be overridden in the derived classes
+    void unbind_impl() {}
+
+    // default implementation called by \ref calculateElementMatrix
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& /*context*/,
+                          RowNode const& /*rowNode*/,
+                          ColNode const& /*colNode*/,
+                          ElementMatrix& /*elementMatrix*/)
+    {
+      error_exit("Needs to be implemented by derived class!");
+    }
+
+    // default implementation called by \ref calculateElementVector
+    template <class Context, class Node, class ElementVector>
+    void getElementVector(Context const& /*context*/,
+                          Node const& /*node*/,
+                          ElementVector& /*elementVector*/)
+    {
+      error_exit("Needs to be implemented by derived class!");
+    }
+
+    /// \brief Return the quadrature degree for a matrix operator.
+    /**
+     * The quadrature degree that is necessary, to integrate the expression
+     * multiplied with (possibly derivatives of) shape functions. Thus it needs
+     * the order of derivatives, this operator implements.
+     **/
+    template <class RowNode, class ColNode>
+    int getDegree(int order, int coeffDegree, RowNode const& rowNode, ColNode const& colNode) const
+    {
+      assert( bound_ );
+      test_warning(coeffDegree >= 0,
+        "polynomial order of coefficient function not determined. Use order 4 by default.");
+
+      int psiDegree = polynomialDegree(rowNode);
+      int phiDegree = polynomialDegree(colNode);
+
+      int degree = psiDegree + phiDegree + (coeffDegree >= 0 ? coeffDegree : 4);
+      if (isSimplex_)
+        degree -= order;
+      if (isAffine_)
+        degree += 1; // oder += (order+1)
+
+      return degree;
+    }
+
+    /// \brief Return the quadrature degree for a vector operator.
+    /**
+     * The quadrature degree that is necessary, to integrate the expression
+     * multiplied with (possibly derivatives of) shape functions. Thus it needs
+     * the order of derivatives, this operator implements.
+     **/
+    template <class Node>
+    int getDegree(int order, int coeffDegree, Node const& node) const
+    {
+      assert( bound_ );
+      test_warning(coeffDegree >= 0,
+        "polynomial order of coefficient function not determined. Use order 4 by default.");
+
+      int psiDegree = polynomialDegree(node);
+
+      int degree = psiDegree + (coeffDegree >= 0 ? coeffDegree : 4);
+      if (isSimplex_)
+        degree -= order;
+      if (isAffine_)
+        degree += 1; // oder += (order+1)
+
+      return degree;
+    }
+
+  protected:
+
+    bool isSimplex_ = false;    //< the bound element is a simplex
+    bool isAffine_ = false;     //< the bound geometry is affine
+    bool bound_ = false;        //< an element is bound to the operator
+  };
+
+
+  /// Generate a \ref LocalOperator from a PreOperator.
+  template <class Derived, class LocalContext, class GridView>
+  auto makeLocalOperator(LocalOperator<Derived, LocalContext> const& localOp, GridView const& /*gridView*/)
+  {
+    return localOp.derived();
+  }
+
+  /// Generate a shared_ptr to a \ref LocalOperator from a PreOperator.
+  template <class Derived, class LocalContext, class GridView>
+  auto makeLocalOperatorPtr(LocalOperator<Derived, LocalContext> const& localOp, GridView const& /*gridView*/)
+  {
+    return std::make_shared<Derived>(localOp.derived());
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/ProblemStat.hpp b/src/amdis/ProblemStat.hpp
index 9352089e83f137088cde0b6136cc5d3922baf007..47e5a63684e9b3e17221be5ce6e2f43e1c70caa1 100644
--- a/src/amdis/ProblemStat.hpp
+++ b/src/amdis/ProblemStat.hpp
@@ -19,6 +19,7 @@
 #include <amdis/Flag.hpp>
 #include <amdis/Initfile.hpp>
 #include <amdis/LinearAlgebra.hpp>
+#include <amdis/LocalAssemblerList.hpp>
 #include <amdis/Marker.hpp>
 #include <amdis/Mesh.hpp>
 #include <amdis/ProblemStatBase.hpp>
diff --git a/src/amdis/ProblemStat.inc.hpp b/src/amdis/ProblemStat.inc.hpp
index 263b5db3d35308019eb2b2eb6146853381c79815..4f08455f00d4d64a853b81d0f33fe518c3cbd767 100644
--- a/src/amdis/ProblemStat.inc.hpp
+++ b/src/amdis/ProblemStat.inc.hpp
@@ -176,7 +176,7 @@ void ProblemStat<Traits>::addMatrixOperator(
   auto i = child(localView_->tree(), makeTreePath(row));
   auto j = child(localView_->tree(), makeTreePath(col));
 
-  auto op = makeGridOperator(preOp, globalBasis_->gridView());
+  auto op = makeLocalOperator<Element>(preOp, globalBasis_->gridView());
   auto localAssembler = makeLocalAssemblerPtr<Element>(std::move(op), i, j);
 
   matrixOperators_[i][j].element.push_back({localAssembler, factor, estFactor});
@@ -201,7 +201,7 @@ void ProblemStat<Traits>::addMatrixOperator(
   auto j = child(localView_->tree(), makeTreePath(col));
   using Intersection = typename GridView::Intersection;
 
-  auto op = makeGridOperator(preOp, globalBasis_->gridView());
+  auto op = makeLocalOperator<Intersection>(preOp, globalBasis_->gridView());
   auto localAssembler = makeLocalAssemblerPtr<Intersection>(std::move(op), i, j);
 
   matrixOperators_[i][j].boundary.push_back({localAssembler, factor, estFactor, b});
@@ -221,7 +221,7 @@ void ProblemStat<Traits>::addVectorOperator(
 
   auto i = child(localView_->tree(), makeTreePath(path));
 
-  auto op = makeGridOperator(preOp, globalBasis_->gridView());
+  auto op = makeLocalOperator<Element>(preOp, globalBasis_->gridView());
   auto localAssembler = makeLocalAssemblerPtr<Element>(std::move(op), i);
 
   rhsOperators_[i].element.push_back({localAssembler, factor, estFactor});
@@ -243,7 +243,7 @@ void ProblemStat<Traits>::addVectorOperator(
   auto i = child(localView_->tree(), makeTreePath(path));
   using Intersection = typename GridView::Intersection;
 
-  auto op = makeGridOperator(preOp, globalBasis_->gridView());
+  auto op = makeLocalOperator<Intersection>(preOp, globalBasis_->gridView());
   auto localAssembler = makeLocalAssemblerPtr<Intersection>(std::move(op), i);
 
   rhsOperators_[i].boundary.push_back({localAssembler, factor, estFactor, b});
diff --git a/src/amdis/QuadratureFactory.hpp b/src/amdis/QuadratureFactory.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2de45d30e36863b6e87d45ad18a62c2d04c856e0
--- /dev/null
+++ b/src/amdis/QuadratureFactory.hpp
@@ -0,0 +1,197 @@
+#pragma once
+
+#include <dune/common/hybridutilities.hh>
+#include <dune/common/std/type_traits.hh>
+#include <dune/geometry/quadraturerules.hh>
+#include <dune/geometry/type.hh>
+
+#include <amdis/GridFunctions.hpp>
+
+namespace AMDiS
+{
+  /// Base class for quadrature factories for localFunctions
+  template <class ctype, int dimension, class LocalFunction>
+  class QuadratureFactory
+  {
+  protected:
+    using QuadratureRule = Dune::QuadratureRule<ctype, dimension>;
+
+  public:
+    virtual ~QuadratureFactory() {}
+
+    /// Bind the rule to a localFunction
+    virtual void bind(LocalFunction const& localFct)
+    {}
+
+    /// Return the quadrature order of the coefficient relates to the localFunction
+    virtual int order() const
+    {
+      return 0;
+    }
+
+    /// Construct a quadrature rule, based on the local geometry-type and the
+    /// polynomial degree of the integrand function.
+    virtual QuadratureRule const& rule(Dune::GeometryType const& type, int degree) const
+    {
+      using QuadratureRules = Dune::QuadratureRules<ctype, dimension>;
+      return QuadratureRules::rule(type, degree);
+    }
+  };
+
+
+  template <class LF>
+  using HasLocalFunctionOrder = decltype( order(std::declval<LF>()) );
+
+
+  /// \brief Factory for quadrature rule, that calculates the coefficient order from
+  /// a localFunction passed to the bind method.
+  template <class ctype, int dimension, class LocalFunction>
+  class QuadFactoryFromLocalFunction
+      : public QuadratureFactory<ctype, dimension, LocalFunction>
+  {
+    using Concept = Dune::Std::is_detected<HasLocalFunctionOrder, LocalFunction>;
+    static_assert(Concept::value,
+      "Polynomial order of GridFunction can not be extracted. Provide an explicit order parameter instead.");
+
+  public:
+    virtual void bind(LocalFunction const& localFct) final
+    {
+      order_ = Dune::Hybrid::ifElse(Concept{},
+        [&](auto id) { return AMDiS::order(id(localFct)); },
+        [] (auto)    { return -1; });
+    }
+
+    virtual int order() const final { return order_; }
+
+  private:
+    int order_ = -1;
+  };
+
+  struct PreQuadFactoryFromLocalFunction {};
+
+  auto makePreQuadratureFactory()
+  {
+    return PreQuadFactoryFromLocalFunction{};
+  }
+
+  /// Generator for \ref QuadFactoryFromLocalFunction. \relates QuadFactoryFromLocalFunction
+  template <class ctype, int dimension, class LocalFunction>
+  auto makeQuadratureFactory(PreQuadFactoryFromLocalFunction const& /*pre*/)
+  {
+    return QuadFactoryFromLocalFunction<ctype, dimension, LocalFunction>{};
+  }
+
+  template <class ctype, int dimension, class LocalFunction>
+  auto makeQuadratureFactoryPtr(PreQuadFactoryFromLocalFunction const& /*pre*/)
+  {
+    using Factory = QuadFactoryFromLocalFunction<ctype, dimension, LocalFunction>;
+    return std::shared_ptr<Factory>(new Factory{});
+  }
+
+
+
+  /// \brief Factory for quadrature rule, that takes to order of the localFunction
+  /// and a quadrature-type
+  template <class ctype, int dimension, class LocalFunction>
+  class QuadFactoryFromOrder
+      : public QuadratureFactory<ctype, dimension, LocalFunction>
+  {
+    using Super = QuadratureFactory<ctype, dimension, LocalFunction>;
+    using QuadratureRule = typename Super::QuadratureRule;
+
+  public:
+    /// Constructor. Takes the order of the localCoefficient and a quadrature-type
+    QuadFactoryFromOrder(int order, Dune::QuadratureType::Enum qt)
+      : order_(order)
+      , qt_(qt)
+    {}
+
+    virtual int order() const final { return order_; }
+
+    virtual QuadratureRule const& rule(Dune::GeometryType const& type, int degree) const final
+    {
+      using QuadratureRules = Dune::QuadratureRules<ctype, dimension>;
+      return QuadratureRules::rule(type, degree, qt_);
+    }
+
+  private:
+    int order_;
+    Dune::QuadratureType::Enum qt_;
+  };
+
+  struct PreQuadFactoryFromOrder
+  {
+    int order;
+    Dune::QuadratureType::Enum qt;
+  };
+
+  auto makePreQuadratureFactory(int order, Dune::QuadratureType::Enum qt = Dune::QuadratureType::GaussLegendre)
+  {
+    return PreQuadFactoryFromOrder{order, qt};
+  }
+
+  /// Generator for \ref QuadFactoryFromOrder. \relates QuadFactoryFromOrder
+  template <class ctype, int dimension, class LocalFunction>
+  auto makeQuadratureFactory(PreQuadFactoryFromOrder const& pre)
+  {
+    return QuadFactoryFromOrder<ctype, dimension, LocalFunction>{pre.order, pre.qt};
+  }
+
+  template <class ctype, int dimension, class LocalFunction>
+  auto makeQuadratureFactoryPtr(PreQuadFactoryFromOrder const& pre)
+  {
+    using Factory = QuadFactoryFromOrder<ctype, dimension, LocalFunction>;
+    return std::make_shared<Factory>(pre.order, pre.qt);
+  }
+
+
+
+  /// \brief Factory for quadrature rule, that is based on an existing rule
+  template <class ctype, int dimension, class LocalFunction>
+  class QuadFactoryFromRule
+      : public QuadratureFactory<ctype, dimension, LocalFunction>
+  {
+    using Super = QuadratureFactory<ctype, dimension, LocalFunction>;
+    using QuadratureRule = typename Super::QuadratureRule;
+
+  public:
+    QuadFactoryFromRule(QuadratureRule const& rule)
+      : rule_(rule)
+    {}
+
+    virtual QuadratureRule const& rule(Dune::GeometryType const& /*type*/, int /*degree*/) const final
+    {
+      return rule_;
+    }
+
+  private:
+    QuadratureRule const& rule_;
+  };
+
+  template <class QuadRule>
+  struct PreQuadFactoryFromRule
+  {
+    QuadRule const& rule;
+  };
+
+  template <class ctype, int dimension>
+  auto makePreQuadratureFactory(Dune::QuadratureRule<ctype, dimension> const& rule)
+  {
+    return PreQuadFactoryFromRule<Dune::QuadratureRule<ctype, dimension>>{rule};
+  }
+
+  /// Generator for \ref QuadFactoryFromRule. \relates QuadFactoryFromRule
+  template <class ctype, int dimension, class LocalFunction, class QuadRule>
+  auto makeQuadratureFactory(PreQuadFactoryFromRule<QuadRule> const& pre)
+  {
+    return QuadFactoryFromRule<ctype, dimension, LocalFunction>{pre.rule};
+  }
+
+  template <class ctype, int dimension, class LocalFunction, class QuadRule>
+  auto makeQuadratureFactoryPtr(PreQuadFactoryFromRule<QuadRule> const& pre)
+  {
+    using Factory = QuadFactoryFromRule<ctype, dimension, LocalFunction>;
+    return std::make_shared<Factory>(pre.rule);
+  }
+
+} // end namespace AMDiS
diff --git a/src/amdis/assembler/ConvectionDiffusionOperator.hpp b/src/amdis/assembler/ConvectionDiffusionOperator.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2f938e7a718a1c353d2052097b8beefb0f0c232
--- /dev/null
+++ b/src/amdis/assembler/ConvectionDiffusionOperator.hpp
@@ -0,0 +1,231 @@
+#pragma once
+
+#include <type_traits>
+
+#include <amdis/LocalOperator.hpp>
+#include <amdis/Output.hpp>
+#include <amdis/common/Utility.hpp>
+#include <amdis/common/ValueCategory.hpp>
+
+namespace AMDiS
+{
+  /**
+   * \addtogroup operators
+   * @{
+   **/
+
+  /// convection-diffusion operator
+  /// <A*grad(u),grad(v)> - <b*u, grad(v)> + <c*u, v> = <f, v> (conserving) or
+  /// <A*grad(u),grad(v)> + <b*grad(u), v> + <c*u, v> = <f, v> (non conserving)
+  template <class LocalContext, class GridFctA, class GridFctB, class GridFctC, class GridFctF, bool conserving = true>
+  class ConvectionDiffusionOperator
+      : public LocalOperator<ConvectionDiffusionOperator<LocalContext, GridFctA, GridFctB, GridFctC, GridFctF, conserving>,
+                             LocalContext>
+  {
+    using A_range_type = typename GridFctA::Range;
+    static_assert( Category::Scalar<A_range_type> || Category::Matrix<A_range_type>,
+      "Expression A(x) must be of scalar or matrix type." );
+    using b_range_type = typename GridFctB::Range;
+    static_assert( Category::Scalar<b_range_type> || Category::Vector<b_range_type>,
+      "Expression b(x) must be of scalar or vector type." );
+    using c_range_type = typename GridFctC::Range;
+    static_assert( Category::Scalar<c_range_type>,
+      "Expression c(x) must be of scalar type." );
+    using f_range_type = typename GridFctF::Range;
+    static_assert( Category::Scalar<f_range_type>,
+      "Expression f(x) must be of scalar type." );
+
+  public:
+    ConvectionDiffusionOperator(GridFctA const& gridFctA, GridFctB const& gridFctB,
+                                GridFctC const& gridFctC, GridFctF const& gridFctF)
+      : gridFctA_(gridFctA)
+      , gridFctB_(gridFctB)
+      , gridFctC_(gridFctC)
+      , gridFctF_(gridFctF)
+    {}
+
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode, ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
+    {
+      static_assert(RowNode::isLeaf && ColNode::isLeaf,
+        "Operator can be applied to Leaf-Nodes only." );
+
+      static_assert(std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>{},
+        "Galerkin operator requires equal finite elements for test and trial space." );
+
+      using LocalBasisType = typename FiniteElementType_t<RowNode>::Traits::LocalBasisType;
+
+      using RangeType = typename LocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename LocalBasisType::Traits::JacobianType;
+
+      auto localFctA = localFunction(gridFctA_); localFctA.bind(context.element());
+      auto localFctB = localFunction(gridFctB_); localFctB.bind(context.element());
+      auto localFctC = localFunction(gridFctC_); localFctC.bind(context.element());
+
+      auto const& localFE = rowNode.finiteElement();
+
+      int quadDeg = std::max({this->getDegree(2,coeffOrder(localFctA),rowNode,colNode),
+                              this->getDegree(1,coeffOrder(localFctB),rowNode,colNode),
+                              this->getDegree(0,coeffOrder(localFctC),rowNode,colNode)});
+
+      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::dimension>;
+      auto const& quad = QuadratureRules::rule(context.type(), quadDeg);
+
+      for (auto const& qp : quad) {
+        // Position of the current quadrature point in the reference element
+        decltype(auto) local = context.local(qp.position());
+
+        // The transposed inverse Jacobian of the map from the reference element to the element
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
+
+        // The multiplicative factor in the integral transformation formula
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
+
+        // the values of the shape functions on the reference element at the quadrature point
+        thread_local std::vector<RangeType> shapeValues;
+        localFE.localBasis().evaluateFunction(local, shapeValues);
+
+        // The gradients of the shape functions on the reference element
+        thread_local std::vector<JacobianType> shapeGradients;
+        localFE.localBasis().evaluateJacobian(local, shapeGradients);
+
+        // Compute the shape function gradients on the real element
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
+
+        for (std::size_t i = 0; i < gradients.size(); ++i)
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
+
+        const auto A = localFctA(local);
+        const auto b = localFctB(local);
+        const auto c = localFctC(local);
+
+        IF_CONSTEXPR(conserving) {
+          for (std::size_t i = 0; i < localFE.size(); ++i) {
+            const int local_i = rowNode.localIndex(i);
+            const auto gradAi = A * gradients[i];
+            const auto gradBi = b * gradients[i];
+            for (std::size_t j = 0; j < localFE.size(); ++j) {
+              const int local_j = colNode.localIndex(j);
+              elementMatrix[local_i][local_j] += (dot(gradAi, gradients[j]) + (c * shapeValues[i] - gradBi) * shapeValues[j]) * factor;
+            }
+          }
+        } else {
+          for (std::size_t i = 0; i < localFE.size(); ++i) {
+            const int local_i = rowNode.localIndex(i);
+            const auto grad_i = A * gradients[i];
+            grad_i += b * shapeValues[i];
+            for (std::size_t j = 0; j < localFE.size(); ++j) {
+              const int local_j = colNode.localIndex(j);
+              elementMatrix[local_i][local_j] += (dot(grad_i, gradients[j]) + c * shapeValues[i] * shapeValues[j]) * factor;
+            }
+          }
+        }
+      }
+
+      localFctA.unbind();
+      localFctB.unbind();
+      localFctC.unbind();
+    }
+
+
+    template <class Context, class Node, class ElementVector>
+    void getElementVector(Context const& context,
+                          Node const& node,
+                          ElementVector& elementVector)
+    {
+      static_assert(Node::isLeaf
+        "Operator can be applied to Leaf-Nodes only." );
+
+      using RangeType = typename FiniteElementType_t<RowNode>::Traits::LocalBasisType::Traits::RangeType;
+
+      auto localFctF = localFunction(gridFctF_); localFctF.bind(context.element());
+
+      auto const& localFE = node.finiteElement();
+
+      int quad_order = this->getDegree(0,coeffOrder(localFctF),node);
+
+      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::dimension>;
+      auto const& quad = QuadratureRules::rule(context.type(), quad_order);
+
+      for (auto const& qp : quad) {
+        // Position of the current quadrature point in the reference element
+        decltype(auto) local = context.local(qp.position());
+
+        // The multiplicative factor in the integral transformation formula
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
+
+        // the values of the shape functions on the reference element at the quadrature point
+        std::vector<RangeType> shapeValues;
+        localFE.localBasis().evaluateFunction(local, shapeValues);
+
+        const auto f = localFctF(local);
+
+        for (std::size_t i = 0; i < localFE.size(); ++i) {
+          const int local_i = rowNode.localIndex(i);
+          elementVector[local_i][local_j] += f * shapeValues[i] * factor;
+        }
+      }
+
+      localFctF.unbind();
+    }
+
+  private:
+
+    template <class LF>
+    using HasLocalFunctionOrder = decltype( order(std::declval<LF>()) );
+
+    template <class LocalFct>
+    int coeffOrder(LocalFct const& localFct)
+    {
+      using Concept = Dune::Std::is_detected<HasLocalFunctionOrder, LocalFunction>;
+      return Dune::Hybrid::ifElse(Concept{},
+        [&](auto id) { return order(id(localFct)); },
+        [] (auto)    { return 0; });
+    }
+
+  private:
+    GridFctA gridFctA;
+    GridFctB gridFctB;
+    GridFctC gridFctC;
+    GridFctF gridFctF;
+  };
+
+  template <class PreGridFctA, class PreGridFctB, class PreGridFctC, class PreGridFctF, bool conserving>
+  struct PreConvectionDiffusionOperator
+  {
+    PreGridFctA gridFctA;
+    PreGridFctB gridFctB;
+    PreGridFctC gridFctC;
+    PreGridFctF gridFctF;
+  };
+
+  template <class PreGridFctA, class PreGridFctB, class PreGridFctC, class PreGridFctF, bool conserving = true>
+  auto convectionDiffusion(PreGridFctA const& gridFctA, PreGridFctB const& gridFctB,
+                           PreGridFctC const& gridFctC, PreGridFctF const& gridFctF,
+                           bool_t<conserving> = {})
+  {
+    using Pre = PreConvectionDiffusionOperator<PreGridFctA, PreGridFctB, PreGridFctC, PreGridFctF, conserving>;
+    return Pre{gridFctA, gridFctB, gridFctC, gridFctF};
+  }
+
+  template <class LocalContext, class... GrdFcts, bool conserving, class GridView>
+  auto makeLocalOperator(PreConvectionDiffusionOperator<GridFcts..., conserving> const& pre, GridView const& gridView)
+  {
+    auto gridFctA = makeGridFunction(pre.gridFctA, gridView);
+    auto gridFctB = makeGridFunction(pre.gridFctB, gridView);
+    auto gridFctC = makeGridFunction(pre.gridFctC, gridView);
+    auto gridFctF = makeGridFunction(pre.gridFctF, gridView);
+
+    using GridFctOp = ConvectionDiffusionOperator<LocalContext,
+      decltype(gridFctA), decltype(gridFctB), decltype(gridFctC), decltype(gridFctF), conserving>;
+
+    GridFctOp localOperator{gridFctA, gridFctB, gridFctC, gridFctF};
+    return localOperator;
+  }
+
+  /** @} **/
+
+} // end namespace AMDiS
diff --git a/src/amdis/assembler/FirstOrderDivTestvecTrial.hpp b/src/amdis/assembler/FirstOrderDivTestvecTrial.hpp
index ecdcc7377f3b5094bd67d5fb738e97cc257029cb..dc49905dec8c8242c1a80952be2bb022275675b4 100644
--- a/src/amdis/assembler/FirstOrderDivTestvecTrial.hpp
+++ b/src/amdis/assembler/FirstOrderDivTestvecTrial.hpp
@@ -18,34 +18,19 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\nabla\cdot\Psi, c\,\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::divtestvec_trial, GridFct, QuadCreator>
-      : public GridFunctionOperator<tag::test_divtrialvec, GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::divtestvec_trial, LocalContext, GridFct>
+      : public GridFunctionOperatorTransposed<GridFunctionOperator<tag::divtestvec_trial, LocalContext, GridFct>,
+                                              GridFunctionOperator<tag::test_divtrialvec, LocalContext, GridFct>>
   {
-    using Transposed = GridFunctionOperator<tag::test_divtrialvec, GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Transposed = GridFunctionOperator<tag::test_divtrialvec, LocalContext, GridFct>;
+    using Super = GridFunctionOperatorTransposed<Self, Transposed>;
 
   public:
-    GridFunctionOperator(tag::divtestvec_trial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Transposed(tag::test_divtrialvec{}, expr, quadCreator)
+    GridFunctionOperator(tag::divtestvec_trial, GridFct const& expr)
+      : Super(tag::test_divtrialvec{}, expr)
     {}
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flagSameFE,
-                                std::integral_constant<bool, sameNode> flagSameNode)
-    {
-      static_assert(RowNode::isPower && ColNode::isLeaf,
-        "ColNode must be Leaf-Node and RowNode must be a Power-Node.");
-
-      auto elementMatrixTransposed = trans(elementMatrix);
-      Transposed::calculateElementMatrix(
-        context, quad, elementMatrixTransposed, colNode, rowNode, flagSameFE, flagSameNode);
-    }
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderGradTestTrial.hpp b/src/amdis/assembler/FirstOrderGradTestTrial.hpp
index 1ca7e92a1d81e7651ebb98657170df40933e495f..6808103e4b6013135f7c278caed611dea2776dcc 100644
--- a/src/amdis/assembler/FirstOrderGradTestTrial.hpp
+++ b/src/amdis/assembler/FirstOrderGradTestTrial.hpp
@@ -18,31 +18,19 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\nabla\psi, \mathbf{b}\,\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::gradtest_trial, GridFct, QuadCreator>
-      : public GridFunctionOperator<tag::test_gradtrial, GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::gradtest_trial, LocalContext, GridFct>
+      : public GridFunctionOperatorTransposed<GridFunctionOperator<tag::gradtest_trial, LocalContext, GridFct>,
+                                              GridFunctionOperator<tag::test_gradtrial, LocalContext, GridFct>>
   {
-    using Transposed = GridFunctionOperator<tag::test_gradtrial, GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Transposed = GridFunctionOperator<tag::test_gradtrial, LocalContext, GridFct>;
+    using Super = GridFunctionOperatorTransposed<Self, Transposed>;
 
   public:
-    GridFunctionOperator(tag::gradtest_trial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Transposed(tag::test_gradtrial{}, expr, quadCreator)
+    GridFunctionOperator(tag::gradtest_trial, GridFct const& expr)
+      : Super(tag::test_gradtrial{}, expr)
     {}
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flagSameFE,
-                                std::integral_constant<bool, sameNode> flagSameNode)
-    {
-      auto elementMatrixTransposed = trans(elementMatrix);
-      Transposed::calculateElementMatrix(
-        context, quad, elementMatrixTransposed, colNode, rowNode, flagSameFE, flagSameNode);
-    }
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderGradTestTrialvec.hpp b/src/amdis/assembler/FirstOrderGradTestTrialvec.hpp
index 4d270a11bdbdc14dca7fe3bc8774435ae5228ca4..83c6c9e86c8eb9dceef7638ca56d3f612eae309e 100644
--- a/src/amdis/assembler/FirstOrderGradTestTrialvec.hpp
+++ b/src/amdis/assembler/FirstOrderGradTestTrialvec.hpp
@@ -18,31 +18,19 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\nabla\psi, c\,\Phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::gradtest_trialvec, GridFct, QuadCreator>
-      : public GridFunctionOperator<tag::testvec_gradtrial, GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::gradtest_trialvec, LocalContext, GridFct>
+      : public GridFunctionOperatorTransposed<GridFunctionOperator<tag::gradtest_trialvec, LocalContext, GridFct>,
+                                              GridFunctionOperator<tag::testvec_gradtrial, LocalContext, GridFct>>
   {
-    using Transposed = GridFunctionOperator<tag::testvec_gradtrial, GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Transposed = GridFunctionOperator<tag::testvec_gradtrial, LocalContext, GridFct>;
+    using Super = GridFunctionOperatorTransposed<Self, Transposed>;
 
   public:
-    GridFunctionOperator(tag::gradtest_trialvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Transposed(tag::testvec_gradtrial{}, expr, quadCreator)
+    GridFunctionOperator(tag::gradtest_trialvec, GridFct const& expr)
+      : Super(tag::testvec_gradtrial{}, expr)
     {}
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flagSameFE,
-                                std::integral_constant<bool, sameNode> flagSameNode)
-    {
-      auto elementMatrixTransposed = trans(elementMatrix);
-      Transposed::calculateElementMatrix(
-        context, quad, elementMatrixTransposed, colNode, rowNode, flagSameFE, flagSameNode);
-    }
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderPartialTestTrial.hpp b/src/amdis/assembler/FirstOrderPartialTestTrial.hpp
index a37fc0437933a01237f3be7ee5d712965b48e0ae..0c9435f8e40c0d80328ab42a914fd1fe6f84273b 100644
--- a/src/amdis/assembler/FirstOrderPartialTestTrial.hpp
+++ b/src/amdis/assembler/FirstOrderPartialTestTrial.hpp
@@ -21,31 +21,19 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\partial_i\psi, c\,\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::partialtest_trial, GridFct, QuadCreator>
-      : public GridFunctionOperator<tag::test_partialtrial, GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::partialtest_trial, LocalContext, GridFct>
+      : public GridFunctionOperatorTransposed<GridFunctionOperator<tag::partialtest_trial, LocalContext, GridFct>,
+                                              GridFunctionOperator<tag::test_partialtrial, LocalContext, GridFct>>
   {
-    using Transposed = GridFunctionOperator<tag::test_partialtrial, GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Transposed = GridFunctionOperator<tag::test_partialtrial, LocalContext, GridFct>;
+    using Super = GridFunctionOperatorTransposed<Self, Transposed>;
 
   public:
-    GridFunctionOperator(tag::partialtest_trial tag, GridFct const& expr, QuadCreator const& quadCreator)
-      : Transposed(tag::test_partialtrial{tag.comp}, expr, quadCreator)
+    GridFunctionOperator(tag::partialtest_trial tag, GridFct const& expr)
+      : Super(tag::test_partialtrial{tag.comp}, expr)
     {}
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flagSameFE,
-                                std::integral_constant<bool, sameNode> flagSameNode)
-    {
-      auto elementMatrixTransposed = trans(elementMatrix);
-      Transposed::calculateElementMatrix(
-        context, quad, elementMatrixTransposed, colNode, rowNode, flagSameFE, flagSameNode);
-    }
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderTestDivTrialvec.hpp b/src/amdis/assembler/FirstOrderTestDivTrialvec.hpp
index d571babf97040af02165c1f6674f6dd1467b64a8..5cdbeab30c818ca90454eeffdba526943da80ad5 100644
--- a/src/amdis/assembler/FirstOrderTestDivTrialvec.hpp
+++ b/src/amdis/assembler/FirstOrderTestDivTrialvec.hpp
@@ -20,28 +20,26 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\psi, c\,\nabla\cdot\Phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test_divtrialvec, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test_divtrialvec, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test_divtrialvec, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::test_divtrialvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 1)
+    GridFunctionOperator(tag::test_divtrialvec, GridFct const& expr)
+      : Super(expr, 1)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isPower,
         "RowNode must be Leaf-Node and ColNode must be a Power-Node.");
@@ -52,35 +50,43 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.child(0).finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using RangeType = typename RowLocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename ColLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        rowLocalFE.localBasis().evaluateFunction(local, shapeValues);
 
         // The gradients of the shape functions on the reference element
-        colLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > colGradients(referenceGradients.size());
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > colGradients(shapeGradients.size());
 
         for (std::size_t i = 0; i < colGradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], colGradients[i]);
+          jacobian.mv(shapeGradients[i][0], colGradients[i]);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          const int local_i = rowNode.localIndex(i);
-          double value = factor * rowShapeValues_[i];
+          const auto local_i = rowNode.localIndex(i);
+          const auto value = factor * shapeValues[i];
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_kj = colNode.child(k).localIndex(j);
+              const auto local_kj = colNode.child(k).localIndex(j);
               elementMatrix[local_i][local_kj] += value * colGradients[j][k];
             }
           }
@@ -88,9 +94,6 @@ namespace AMDiS
       }
 
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderTestGradTrial.hpp b/src/amdis/assembler/FirstOrderTestGradTrial.hpp
index a4ae5383cef98820a238a28ea2d6cc659c1ecf5e..bccf890d72ed0d0289b9df7755692603e6a1e0e3 100644
--- a/src/amdis/assembler/FirstOrderTestGradTrial.hpp
+++ b/src/amdis/assembler/FirstOrderTestGradTrial.hpp
@@ -20,28 +20,26 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\psi, \mathbf{b}\cdot\nabla\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test_gradtrial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test_gradtrial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test_gradtrial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Vector<typename GridFct::Range>, "Expression must be of vector type." );
 
   public:
-    GridFunctionOperator(tag::test_gradtrial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 1)
+    GridFunctionOperator(tag::test_gradtrial, GridFct const& expr)
+      : Super(expr, 1)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
@@ -49,44 +47,48 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using RangeType = typename RowLocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename ColLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const auto b = Super::coefficient(local);
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        rowLocalFE.localBasis().evaluateFunction(local, shapeValues);
 
         // The gradients of the shape functions on the reference element
-        colLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > colGradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > colGradients(shapeGradients.size());
         for (std::size_t i = 0; i < colGradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], colGradients[i]);
+          jacobian.mv(shapeGradients[i][0], colGradients[i]);
 
         for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-          const int local_j = colNode.localIndex(j);
-          double value = factor * (b * colGradients[j]);
+          const auto local_j = colNode.localIndex(j);
+          const auto value = factor * (b * colGradients[j]);
           for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-            const int local_i = rowNode.localIndex(i);
-            elementMatrix[local_i][local_j] += value * rowShapeValues_[i];
+            const auto local_i = rowNode.localIndex(i);
+            elementMatrix[local_i][local_j] += value * shapeValues[i];
           }
         }
       }
 
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderTestPartialTrial.hpp b/src/amdis/assembler/FirstOrderTestPartialTrial.hpp
index 2d900f5dbb17a585903486e9ca9275a9136c29e8..d69dcb68b094c22ae90b48a6fc41590e93015f21 100644
--- a/src/amdis/assembler/FirstOrderTestPartialTrial.hpp
+++ b/src/amdis/assembler/FirstOrderTestPartialTrial.hpp
@@ -23,29 +23,27 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\psi, c\,\partial_i\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test_partialtrial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test_partialtrial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test_partialtrial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::test_partialtrial tag, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 1)
+    GridFunctionOperator(tag::test_partialtrial tag, GridFct const& expr)
+      : Super(expr, 1)
       , comp_(tag.comp)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
@@ -53,48 +51,54 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.finiteElement();
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+
+      using RangeType = typename RowLocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename ColLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
         assert(jacobian.M() == Context::dim);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
-        double c = Super::coefficient(local);
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
+        const auto c = Super::coefficient(local);
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        rowLocalFE.localBasis().evaluateFunction(local, shapeValues);
 
         // The gradients of the shape functions on the reference element
-        std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
-        colLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<double> colPartial(referenceGradients.size());
-
+        thread_local std::vector<RangeFieldType> colPartial(shapeGradients.size());
         for (std::size_t i = 0; i < colPartial.size(); ++i) {
-          colPartial[i] = jacobian[comp_][0] * referenceGradients[i][0][0];
+          colPartial[i] = jacobian[comp_][0] * shapeGradients[i][0][0];
           for (std::size_t j = 1; j < jacobian.M(); ++j)
-            colPartial[i] += jacobian[comp_][j] * referenceGradients[i][0][j];
+            colPartial[i] += jacobian[comp_][j] * shapeGradients[i][0][j];
         }
 
         for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-          const int local_j = colNode.localIndex(j);
-          double value = factor * (c * colPartial[j]);
+          const auto local_j = colNode.localIndex(j);
+          const auto value = factor * (c * colPartial[j]);
           for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-            const int local_i = rowNode.localIndex(i);
-            elementMatrix[local_i][local_j] += value * rowShapeValues_[i];
+            const auto local_i = rowNode.localIndex(i);
+            elementMatrix[local_i][local_j] += value * shapeValues[i];
           }
         }
       }
-
     }
 
   private:
     std::size_t comp_;
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/FirstOrderTestvecGradTrial.hpp b/src/amdis/assembler/FirstOrderTestvecGradTrial.hpp
index 2bfd6d52d1bbda560b094803ea272d6325dd4de4..d06a44dbc79a2538e0933246edf81a30c1e80f98 100644
--- a/src/amdis/assembler/FirstOrderTestvecGradTrial.hpp
+++ b/src/amdis/assembler/FirstOrderTestvecGradTrial.hpp
@@ -20,28 +20,26 @@ namespace AMDiS
 
 
   /// first-order operator \f$ \langle\Psi, c\,\nabla\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::testvec_gradtrial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::testvec_gradtrial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::testvec_gradtrial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::testvec_gradtrial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 1)
+    GridFunctionOperator(tag::testvec_gradtrial, GridFct const& expr)
+      : Super(expr, 1)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isPower && ColNode::isLeaf,
         "ColNode must be Leaf-Node and RowNode must be a Power-Node.");
@@ -52,35 +50,42 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.child(0).finiteElement();
       auto const& colLocalFE = colNode.finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using RangeType = typename RowLocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename ColLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        rowLocalFE.localBasis().evaluateFunction(local, shapeValues);
 
         // The gradients of the shape functions on the reference element
-        colLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > colGradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > colGradients(shapeGradients.size());
         for (std::size_t i = 0; i < colGradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], colGradients[i]);
+          jacobian.mv(shapeGradients[i][0], colGradients[i]);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          double value = factor * rowShapeValues_[i];
+          const auto value = factor * shapeValues[i];
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            const int local_j = colNode.localIndex(j);
+            const auto local_j = colNode.localIndex(j);
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_ki = rowNode.child(k).localIndex(i);
+              const auto local_ki = rowNode.child(k).localIndex(i);
               elementMatrix[local_ki][local_j] += value * colGradients[j][k];
             }
           }
@@ -88,9 +93,6 @@ namespace AMDiS
       }
 
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/SecondOrderDivTestvecDivTrialvec.hpp b/src/amdis/assembler/SecondOrderDivTestvecDivTrialvec.hpp
index 6a4a62726ae5190576326379eabe0b658732ace1..0e841d53cfef6760ae18741161538680b1922dcf 100644
--- a/src/amdis/assembler/SecondOrderDivTestvecDivTrialvec.hpp
+++ b/src/amdis/assembler/SecondOrderDivTestvecDivTrialvec.hpp
@@ -20,70 +20,93 @@ namespace AMDiS
 
 
   /// second-order operator \f$ \langle\nabla\cdot\Psi, c\,\nabla\cdot\Phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::divtestvec_divtrialvec, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::divtestvec_divtrialvec, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::divtestvec_divtrialvec, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::divtestvec_divtrialvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 2)
+    GridFunctionOperator(tag::divtestvec_divtrialvec, GridFct const& expr)
+      : Super(expr, 2)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isPower && ColNode::isPower,
         "Operator can be applied to Power-Nodes only.");
 
+      const bool sameFE = std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>::value;
+      const bool sameNode = rowNode.treeIndex() == colNode.treeIndex();
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      if (sameFE && sameNode)
+        getElementMatrixOptimized(context, quad, rowNode, colNode, elementMatrix);
+      else
+        getElementMatrixStandard(context, quad, rowNode, colNode, elementMatrix);
+    }
+
+  protected:
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixStandard(Context const& context,
+                                  QuadratureRule const& quad,
+                                  RowNode const& rowNode,
+                                  ColNode const& colNode,
+                                  ElementMatrix& elementMatrix)
+    {
       static const std::size_t CHILDREN = RowNode::CHILDREN;
       static_assert( RowNode::CHILDREN == ColNode::CHILDREN, "" );
 
       auto const& rowLocalFE = rowNode.child(0).finiteElement();
       auto const& colLocalFE = colNode.child(0).finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > rowReferenceGradients;
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > colReferenceGradients;
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+
+      using RowFieldType = typename RowLocalBasisType::Traits::RangeFieldType;
+      using ColFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using RowJacobianType = typename RowLocalBasisType::Traits::JacobianType;
+      using ColJacobianType = typename ColLocalBasisType::Traits::JacobianType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
         // The gradients of the shape functions on the reference element
-        rowLocalFE.localBasis().evaluateJacobian(local, rowReferenceGradients);
-        colLocalFE.localBasis().evaluateJacobian(local, colReferenceGradients);
+        thread_local std::vector<RowJacobianType> rowShapeGradients;
+        rowLocalFE.localBasis().evaluateJacobian(local, rowShapeGradients);
 
-        // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > rowGradients(rowReferenceGradients.size());
-        std::vector<Dune::FieldVector<double,Context::dow> > colGradients(colReferenceGradients.size());
+        thread_local std::vector<ColJacobianType> colShapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, colShapeGradients);
 
+        // Compute the shape function gradients on the real element
+        thread_local std::vector<Dune::FieldVector<RowFieldType,Context::dow> > rowGradients(rowShapeGradients.size());
         for (std::size_t i = 0; i < rowGradients.size(); ++i)
-          jacobian.mv(rowReferenceGradients[i][0], rowGradients[i]);
+          jacobian.mv(rowShapeGradients[i][0], rowGradients[i]);
 
+        thread_local std::vector<Dune::FieldVector<ColFieldType,Context::dow> > colGradients(colShapeGradients.size());
         for (std::size_t i = 0; i < colGradients.size(); ++i)
-          jacobian.mv(colReferenceGradients[i][0], colGradients[i]);
+          jacobian.mv(colShapeGradients[i][0], colGradients[i]);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_ki = rowNode.child(k).localIndex(i);
-              const int local_kj = colNode.child(k).localIndex(j);
+              const auto local_ki = rowNode.child(k).localIndex(i);
+              const auto local_kj = colNode.child(k).localIndex(j);
               elementMatrix[local_ki][local_kj] += factor * rowGradients[i][k] * colGradients[j][k];
             }
           }
@@ -92,52 +115,48 @@ namespace AMDiS
     }
 
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& node,
-                                ColNode const& /*colNode*/,
-                                std::true_type /*sameFE*/,
-                                std::true_type /*sameNode*/)
+    template <class Context, class QuadratureRule, class Node, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   Node const& node,
+                                   Node const& /*colNode*/,
+                                   ElementMatrix& elementMatrix)
     {
-      static_assert( std::is_same<typename RowNode::NodeTag, Dune::TypeTree::PowerNodeTag>::value &&
-                     std::is_same<typename ColNode::NodeTag, Dune::TypeTree::PowerNodeTag>::value, "" );
-
-      static const std::size_t CHILDREN = RowNode::CHILDREN;
+      static const std::size_t CHILDREN = Node::CHILDREN;
 
       auto const& localFE = node.child(0).finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename LocalBasisType::Traits::JacobianType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
         // The gradients of the shape functions on the reference element
-        localFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        localFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > gradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
         for (std::size_t i = 0; i < gradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], gradients[i]);
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
 
         for (std::size_t k = 0; k < CHILDREN; ++k) {
           for (std::size_t i = 0; i < localFE.size(); ++i) {
-            const int local_ki = node.child(k).localIndex(i);
-            double value = factor * gradients[i][k];
+            const auto local_ki = node.child(k).localIndex(i);
+            const auto value = factor * gradients[i][k];
             elementMatrix[local_ki][local_ki] += value * gradients[i][k];
 
             for (std::size_t j = i+1; j < localFE.size(); ++j) {
-              const int local_kj = node.child(k).localIndex(j);
+              const auto local_kj = node.child(k).localIndex(j);
               elementMatrix[local_ki][local_kj] += value * gradients[j][k];
               elementMatrix[local_kj][local_ki] += value * gradients[j][k];
             }
diff --git a/src/amdis/assembler/SecondOrderGradTestGradTrial.hpp b/src/amdis/assembler/SecondOrderGradTestGradTrial.hpp
index bfb3943d2eedc12cdbb29491b398e3ac190b9dc8..d8f6ea1ddda6a0418390ee8e290e1c8f56953066 100644
--- a/src/amdis/assembler/SecondOrderGradTestGradTrial.hpp
+++ b/src/amdis/assembler/SecondOrderGradTestGradTrial.hpp
@@ -20,128 +20,131 @@ namespace AMDiS
 
 
   /// second-order operator \f$ \langle\nabla\psi, c\,\nabla\phi\rangle \f$, or \f$ \langle\nabla\psi, A\,\nabla\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::gradtest_gradtrial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::gradtest_gradtrial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::gradtest_gradtrial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     using expr_value_type = typename GridFct::Range;
     static_assert( Category::Scalar<expr_value_type> || Category::Matrix<expr_value_type>,
       "Expression must be of scalar or matrix type." );
 
   public:
-    GridFunctionOperator(tag::gradtest_gradtrial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 2)
+    GridFunctionOperator(tag::gradtest_gradtrial, GridFct const& expr)
+      : Super(expr, 2)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::false_type /*sameNode*/)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
 
-      auto const& rowLocalFE = rowNode.finiteElement();
-      auto const& colLocalFE = colNode.finiteElement();
+      const bool sameFE = std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>::value;
+      const bool sameNode = rowNode.treeIndex() == colNode.treeIndex();
+      using Category = ValueCategory_t<typename GridFct::Range>;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      if (sameFE && sameNode)
+        getElementMatrixOptimized(context, quad, rowNode, colNode, elementMatrix, Category{});
+      else if (sameFE)
+        getElementMatrixStandard(context, quad, rowNode, colNode, elementMatrix);
+      else
+        error_exit("Not implemented: currently only the implementation for equal fespaces available");
+    }
+
+  protected:
+
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixStandard(Context const& context,
+                                  QuadratureRule const& quad,
+                                  RowNode const& rowNode,
+                                  ColNode const& colNode,
+                                  ElementMatrix& elementMatrix)
+    {
+      auto const& localFE = rowNode.finiteElement();
 
-      test_exit( sameFE, "Not implemented: currently only the implementation for equal fespaces available" );
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename LocalBasisType::Traits::JacobianType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const auto exprValue = Super::coefficient(local);
 
         // The gradients of the shape functions on the reference element
-        thread_local std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
-        rowLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        localFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        thread_local std::vector<Dune::FieldVector<double,Context::dow> > gradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
         for (std::size_t i = 0; i < gradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], gradients[i]);
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
 
-        for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          const int local_i = rowNode.localIndex(i);
-          for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            const int local_j = colNode.localIndex(j);
+        for (std::size_t i = 0; i < localFE.size(); ++i) {
+          const auto local_i = rowNode.localIndex(i);
+          for (std::size_t j = 0; j < localFE.size(); ++j) {
+            const auto local_j = colNode.localIndex(j);
             elementMatrix[local_i][local_j] += eval(exprValue, factor, gradients[i], gradients[j]);
           }
         }
       }
     }
 
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& node,
-                                ColNode const& /*colNode*/,
-                                std::true_type /*sameFE*/,
-                                std::true_type /*sameNode*/)
-    {
-      static_assert(RowNode::isLeaf && ColNode::isLeaf,
-        "Operator can be applied to Leaf-Nodes only.");
-
-      using Category = ValueCategory_t<typename GridFct::Range>;
-      calcElementMatrix(context, quad, elementMatrix, node, Category{});
-    }
-
-  protected:
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode>
-    void calcElementMatrix(Context const& context,
-                           QuadratureRule const& quad,
-                           ElementMatrix& elementMatrix,
-                           RowNode const& node,
-                           tag::scalar)
+    template <class Context, class QuadratureRule, class Node, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   Node const& node,
+                                   Node const& /*colNode*/,
+                                   ElementMatrix& elementMatrix,
+                                   tag::scalar)
     {
       auto const& localFE = node.finiteElement();
-      thread_local std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename LocalBasisType::Traits::JacobianType;
+
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
         // The gradients of the shape functions on the reference element
-        localFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        localFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        thread_local std::vector<Dune::FieldVector<double,Context::dow> > gradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
         for (std::size_t i = 0; i < gradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], gradients[i]);
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          const int local_i = node.localIndex(i);
+          const auto local_i = node.localIndex(i);
 
           elementMatrix[local_i][local_i] += factor * (gradients[i] * gradients[i]);
 
           for (std::size_t j = i+1; j < localFE.size(); ++j) {
-            const int local_j = node.localIndex(j);
-            double value = factor * (gradients[i] * gradients[j]);
+            const auto local_j = node.localIndex(j);
+            const auto value = factor * (gradients[i] * gradients[j]);
 
             elementMatrix[local_i][local_j] += value;
             elementMatrix[local_j][local_i] += value;
@@ -150,42 +153,44 @@ namespace AMDiS
       }
     }
 
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode>
-    void calcElementMatrix(Context const& context,
-                           QuadratureRule const& quad,
-                           ElementMatrix& elementMatrix,
-                           RowNode const& node,
-                           tag::matrix)
+    template <class Context, class QuadratureRule, class Node, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   Node const& node,
+                                   Node const& /*colNode*/,
+                                   ElementMatrix& elementMatrix,
+                                   tag::matrix)
     {
       auto const& localFE = node.finiteElement();
-      thread_local std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeFieldType = typename LocalBasisType::Traits::RangeFieldType;
+      using JacobianType = typename LocalBasisType::Traits::JacobianType;
+
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const auto exprValue = Super::coefficient(local);
 
         // The gradients of the shape functions on the reference element
-        localFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<JacobianType> shapeGradients;
+        localFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        thread_local std::vector<Dune::FieldVector<double,Context::dow> > gradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
         for (std::size_t i = 0; i < gradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], gradients[i]);
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          const int local_i = node.localIndex(i);
+          const auto local_i = node.localIndex(i);
           for (std::size_t j = 0; j < localFE.size(); ++j) {
-            const int local_j = node.localIndex(j);
+            const auto local_j = node.localIndex(j);
             elementMatrix[local_i][local_j] += eval(exprValue, factor, gradients[i], gradients[j]);
           }
         }
@@ -194,20 +199,22 @@ namespace AMDiS
 
   protected:
 
-    template <int dow>
-    double eval(Dune::FieldVector<double,1> const& scalar, double factor,
-                Dune::FieldVector<double,dow> const& grad_test,
-                Dune::FieldVector<double,dow> const& grad_trial) const
+    template <class S, class F, class T, int dow,
+      std::enable_if_t<Category::Scalar<S>,int> = 0>
+    T eval(S const& scalar, F factor,
+           Dune::FieldVector<T,dow> const& grad_test,
+           Dune::FieldVector<T,dow> const& grad_trial) const
     {
       return (scalar * factor) * (grad_test * grad_trial);
     }
 
-    template <int dow>
-    double eval(Dune::FieldMatrix<double,dow,dow> const& M, double factor,
-                Dune::FieldVector<double,dow> const& grad_test,
-                Dune::FieldVector<double,dow> const& grad_trial) const
+    template <class M, class F, class T, int dow,
+      std::enable_if_t<Category::Matrix<M>,int> = 0>
+    T eval(M const& mat, F factor,
+           Dune::FieldVector<T,dow> const& grad_test,
+           Dune::FieldVector<T,dow> const& grad_trial) const
     {
-      return factor * (grad_test * (M * grad_trial));
+      return factor * (grad_test * (mat * grad_trial));
     }
   };
 
diff --git a/src/amdis/assembler/SecondOrderPartialTestPartialTrial.hpp b/src/amdis/assembler/SecondOrderPartialTestPartialTrial.hpp
index f5c548add90cd01e37592c8e94de651665caa58b..6539acf8ce1ec785c1a2cc689884f5e9fb8a2295 100644
--- a/src/amdis/assembler/SecondOrderPartialTestPartialTrial.hpp
+++ b/src/amdis/assembler/SecondOrderPartialTestPartialTrial.hpp
@@ -24,30 +24,28 @@ namespace AMDiS
 
 
   /// second-order operator \f$ \langle\partial_i\psi, c\,\partial_j\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::partialtest_partialtrial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::partialtest_partialtrial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::partialtest_partialtrial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::partialtest_partialtrial tag, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 2)
+    GridFunctionOperator(tag::partialtest_partialtrial tag, GridFct const& expr)
+      : Super(expr, 2)
       , compTest_(tag.comp_test)
       , compTrial_(tag.comp_trial)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
@@ -55,46 +53,52 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.finiteElement();
 
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > rowReferenceGradients;
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > colReferenceGradients;
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using RowFieldType = typename RowLocalBasisType::Traits::RangeFieldType;
+      using ColFieldType = typename ColLocalBasisType::Traits::RangeFieldType;
+      using RowJacobianType = typename RowLocalBasisType::Traits::JacobianType;
+      using ColJacobianType = typename ColLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
-        double c = Super::coefficient(local);
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
+        const auto c = Super::coefficient(local);
 
         // The gradients of the shape functions on the reference element
-        rowLocalFE.localBasis().evaluateJacobian(local, rowReferenceGradients);
-        colLocalFE.localBasis().evaluateJacobian(local, colReferenceGradients);
+        thread_local std::vector<RowJacobianType> rowShapeGradients;
+        rowLocalFE.localBasis().evaluateJacobian(local, rowShapeGradients);
+        thread_local std::vector<ColJacobianType> colShapeGradients;
+        colLocalFE.localBasis().evaluateJacobian(local, colShapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<double> rowPartial(rowReferenceGradients.size());
-        std::vector<double> colPartial(colReferenceGradients.size());
-
-        // transform gradients to global element
+        thread_local std::vector<RowFieldType> rowPartial(rowShapeGradients.size());
         for (std::size_t i = 0; i < rowPartial.size(); ++i) {
-          rowPartial[i] = jacobian[compTest_][0] * rowReferenceGradients[i][0][0];
+          rowPartial[i] = jacobian[compTest_][0] * rowShapeGradients[i][0][0];
           for (std::size_t j = 1; j < jacobian.cols(); ++j)
-            rowPartial[i] += jacobian[compTest_][j] * rowReferenceGradients[i][0][j];
+            rowPartial[i] += jacobian[compTest_][j] * rowShapeGradients[i][0][j];
         }
 
+        thread_local std::vector<ColFieldType> colPartial(colShapeGradients.size());
         for (std::size_t i = 0; i < colPartial.size(); ++i) {
-          colPartial[i] = jacobian[compTrial_][0] * colReferenceGradients[i][0][0];
+          colPartial[i] = jacobian[compTrial_][0] * colShapeGradients[i][0][0];
           for (std::size_t j = 1; j < jacobian.cols(); ++j)
-            colPartial[i] += jacobian[compTrial_][j] * colReferenceGradients[i][0][j];
+            colPartial[i] += jacobian[compTrial_][j] * colShapeGradients[i][0][j];
         }
 
         for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-          const int local_j = colNode.localIndex(j);
-          double value = factor * (c * colPartial[j]);
+          const auto local_j = colNode.localIndex(j);
+          const auto value = factor * (c * colPartial[j]);
           for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-            const int local_i = rowNode.localIndex(i);
+            const auto local_i = rowNode.localIndex(i);
             elementMatrix[local_i][local_j] += value * rowPartial[i];
           }
         }
diff --git a/src/amdis/assembler/StokesOperator.hpp b/src/amdis/assembler/StokesOperator.hpp
index 46c191a66bfd1d42c3d558a71695fe714781cde0..b9dd503273666303b696d2b6a01effdcf4220366 100644
--- a/src/amdis/assembler/StokesOperator.hpp
+++ b/src/amdis/assembler/StokesOperator.hpp
@@ -20,27 +20,26 @@ namespace AMDiS
 
 
   /// Stokes operator \f$ \langle\nabla\mathbf{v}, \nu \nabla\mathbf{u}\rangle + \langle\nabla\cdot\mathbf{v}, p\rangle + \langle q, \langle\nabla\cdot\mathbf{u}\rangle \f$
-  template <class ViscosityExpr, class QuadCreator>
-  class GridFunctionOperator<tag::stokes, ViscosityExpr, QuadCreator>
-      : public GridFunctionOperatorBase<ViscosityExpr, QuadCreator>
+  template <class LocalContext, class ViscosityExpr>
+  class GridFunctionOperator<tag::stokes, LocalContext, ViscosityExpr>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::stokes, LocalContext, ViscosityExpr>,
+                                        LocalContext, ViscosityExpr>
   {
-    using Super = GridFunctionOperatorBase<ViscosityExpr, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, ViscosityExpr>;
 
     static_assert( Category::Scalar<typename ViscosityExpr::Range>, "Viscosity must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::stokes, ViscosityExpr const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 1)
+    GridFunctionOperator(tag::stokes, ViscosityExpr const& expr)
+      : Super(expr, 1)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class Node, class Flag1, class Flag2>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                Node const& tree,
-                                Node const& /*colNode*/,
-                                Flag1, Flag2)
+    template <class Context, class Node, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          Node const& tree,
+                          Node const& /*colNode*/,
+                          ElementMatrix& elementMatrix)
     {
       using VelocityNode = typename Node::template Child<0>::type;
       using PressureNode = typename Node::template Child<1>::type;
@@ -51,44 +50,50 @@ namespace AMDiS
       auto const& velocityLocalFE = tree.child(_0,0).finiteElement();
       auto const& pressureLocalFE = tree.child(_1).finiteElement();
 
-      std::vector<Dune::FieldVector<double,1>> pressureValues;
-      std::vector<Dune::FieldMatrix<double,1,Context::dim> > referenceGradients;
+      using VelocityLocalBasisType = typename std::decay_t<decltype(velocityLocalFE)>::Traits::LocalBasisType;
+      using PressureLocalBasisType = typename std::decay_t<decltype(pressureLocalFE)>::Traits::LocalBasisType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using PressureRange = typename PressureLocalBasisType::Traits::RangeType;
+      using RangeFieldType = typename VelocityLocalBasisType::Traits::RangeFieldType;
+      using VelocityJacobian = typename VelocityLocalBasisType::Traits::JacobianType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), tree, tree);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The transposed inverse Jacobian of the map from the reference element to the element
-        const auto jacobian = context.geometry.jacobianInverseTransposed(local);
+        const auto jacobian = context.geometry().jacobianInverseTransposed(local);
 
         // The multiplicative factor in the integral transformation formula
-        const double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
-        const double vel_factor = Super::coefficient(local) * factor;
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
+        const auto vel_factor = Super::coefficient(local) * factor;
 
         // The gradients of the shape functions on the reference element
-        velocityLocalFE.localBasis().evaluateJacobian(local, referenceGradients);
+        thread_local std::vector<VelocityJacobian> shapeGradients;
+        velocityLocalFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        std::vector<Dune::FieldVector<double,Context::dow> > gradients(referenceGradients.size());
-
+        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
         for (std::size_t i = 0; i < gradients.size(); ++i)
-          jacobian.mv(referenceGradients[i][0], gradients[i]);
+          jacobian.mv(shapeGradients[i][0], gradients[i]);
 
+        thread_local std::vector<PressureRange> pressureValues;
         pressureLocalFE.localBasis().evaluateFunction(local, pressureValues);
 
         // <viscosity * grad(u), grad(v)>
         for (std::size_t i = 0; i < velocityLocalFE.size(); ++i) {
-          auto value_ii = vel_factor * (gradients[i] * gradients[i]);
+          const auto value_ii = vel_factor * (gradients[i] * gradients[i]);
           for (std::size_t k = 0; k < Context::dow; ++k) {
-            std::size_t local_ki = tree.child(_0,k).localIndex(i);
+            const auto local_ki = tree.child(_0,k).localIndex(i);
             elementMatrix[local_ki][local_ki] += value_ii;
           }
 
           for (std::size_t j = i+1; j < velocityLocalFE.size(); ++j) {
-            auto value = vel_factor * (gradients[i] * gradients[j]);
+            const auto value = vel_factor * (gradients[i] * gradients[j]);
             for (std::size_t k = 0; k < Context::dow; ++k) {
-              std::size_t local_ki = tree.child(_0,k).localIndex(i);
-              std::size_t local_kj = tree.child(_0,k).localIndex(j);
+              const auto local_ki = tree.child(_0,k).localIndex(i);
+              const auto local_kj = tree.child(_0,k).localIndex(j);
               elementMatrix[local_ki][local_kj] += value;
               elementMatrix[local_kj][local_ki] += value;
             }
@@ -98,10 +103,10 @@ namespace AMDiS
         // <p, div(v)> + <div(u), q>
         for (std::size_t i = 0; i < velocityLocalFE.size(); ++i) {
           for (std::size_t j = 0; j < pressureLocalFE.size(); ++j) {
-            auto value = factor * pressureValues[j];
+            const auto value = factor * pressureValues[j];
             for (std::size_t k = 0; k < Context::dow; ++k) {
-              std::size_t local_v = tree.child(_0,k).localIndex(i);
-              std::size_t local_p = tree.child(_1).localIndex(j);
+              const auto local_v = tree.child(_0,k).localIndex(i);
+              const auto local_p = tree.child(_1).localIndex(j);
 
               elementMatrix[local_v][local_p] += gradients[i][k] * value;
               elementMatrix[local_p][local_v] += gradients[i][k] * value;
diff --git a/src/amdis/assembler/ZeroOrderTest.hpp b/src/amdis/assembler/ZeroOrderTest.hpp
index fd6f6786d6379430cff6b018b3df8d758c6c2588..5639f0c57c26e05bf7f862c823ba9d9d29bc22ef 100644
--- a/src/amdis/assembler/ZeroOrderTest.hpp
+++ b/src/amdis/assembler/ZeroOrderTest.hpp
@@ -19,48 +19,50 @@ namespace AMDiS
 
 
   /// zero-order vector-operator \f$ (c\, \psi) \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::test, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 0)
+    GridFunctionOperator(tag::test, GridFct const& expr)
+      : Super(expr, 0)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementVector, class Node>
-    void calculateElementVector(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementVector& elementVector,
-                                Node const& node)
+    template <class Context, class Node, class ElementVector>
+    void getElementVector(Context const& context,
+                          Node const& node,
+                          ElementVector& elementVector)
     {
       static_assert(Node::isLeaf, "Operator can be applied to Leaf-Nodes only");
 
       auto const& localFE = node.finiteElement();
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeType = typename LocalBasisType::Traits::RangeType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), node);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
-        localFE.localBasis().evaluateFunction(local, shapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        localFE.localBasis().evaluateFunction(local, shapeValues);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          const int local_i = node.localIndex(i);
-          elementVector[local_i] += factor * shapeValues_[i];
+          const auto local_i = node.localIndex(i);
+          elementVector[local_i] += factor * shapeValues[i];
         }
       }
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> shapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/ZeroOrderTestTrial.hpp b/src/amdis/assembler/ZeroOrderTestTrial.hpp
index d7df01aacf32518142e2c33126a8a22f17d46bb4..47b0e4d3676e9165604c1c7ef475f07d5f86e52c 100644
--- a/src/amdis/assembler/ZeroOrderTestTrial.hpp
+++ b/src/amdis/assembler/ZeroOrderTestTrial.hpp
@@ -19,28 +19,44 @@ namespace AMDiS
 
 
   /// zero-order operator \f$ \langle\psi, c\,\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test_trial, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test_trial, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test_trial, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Scalar<typename GridFct::Range>, "Expression must be of scalar type." );
 
   public:
-    GridFunctionOperator(tag::test_trial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 0)
+    GridFunctionOperator(tag::test_trial, GridFct const& expr)
+      : Super(expr, 0)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::false_type /*sameNode*/)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
+    {
+      const bool sameFE = std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>::value;
+      const bool sameNode = rowNode.treeIndex() == colNode.treeIndex();
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      if (sameFE && sameNode)
+        getElementMatrixOptimized(context, quad, rowNode, colNode, elementMatrix);
+      else
+        getElementMatrixStandard(context, quad, rowNode, colNode, elementMatrix);
+    }
+
+  protected:
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixStandard(Context const& context,
+                                  QuadratureRule const& quad,
+                                  RowNode const& rowNode,
+                                  ColNode const& colNode,
+                                  ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
@@ -48,26 +64,35 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.finiteElement();
 
-      auto* rowShapeValues = &rowShapeValues_;
-      auto* colShapeValues = (sameFE ? &rowShapeValues_ : &colShapeValues_);
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+      using RowRangeType = typename RowLocalBasisType::Traits::RangeType;
+      using ColRangeType = typename ColLocalBasisType::Traits::RangeType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      thread_local std::vector<RowRangeType> rowShapeValueBuffer;
+      thread_local std::vector<ColRangeType> colShapeValueBuffer;
+
+      const bool sameFE = std::is_same<decltype(rowLocalFE),decltype(colLocalFE)>::value;
+      auto* rowShapeValues = &rowShapeValueBuffer;
+      auto* colShapeValues = (sameFE ? &rowShapeValueBuffer : &colShapeValueBuffer);
+
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValueBuffer);
         if (!sameFE)
-          colLocalFE.localBasis().evaluateFunction(local, colShapeValues_);
+          colLocalFE.localBasis().evaluateFunction(local, colShapeValueBuffer);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          const int local_i = rowNode.localIndex(i);
-          double value = factor * (*rowShapeValues)[i];
+          const auto local_i = rowNode.localIndex(i);
+          const auto value = factor * (*rowShapeValues)[i];
 
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            const int local_j = colNode.localIndex(j);
+            const auto local_j = colNode.localIndex(j);
             elementMatrix[local_i][local_j] += value * (*colShapeValues)[j];
           }
         }
@@ -76,38 +101,39 @@ namespace AMDiS
 
 
     template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& node,
-                                ColNode const& /*colNode*/,
-                                std::true_type /*sameFE*/,
-                                std::true_type /*sameNode*/)
+              class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   RowNode const& node,
+                                   ColNode const& /*colNode*/,
+                                   ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isLeaf,
         "Operator can be applied to Leaf-Nodes only.");
 
       auto const& localFE = node.finiteElement();
-      auto& shapeValues = rowShapeValues_;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeType = typename LocalBasisType::Traits::RangeType;
+
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        const double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
+        thread_local std::vector<RangeType> shapeValues;
         localFE.localBasis().evaluateFunction(local, shapeValues);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          const int local_i = node.localIndex(i);
+          const auto local_i = node.localIndex(i);
 
-          double value = factor * shapeValues[i];
+          const auto value = factor * shapeValues[i];
           elementMatrix[local_i][local_i] += value * shapeValues[i];
 
           for (std::size_t j = i+1; j < localFE.size(); ++j) {
-            const int local_j = node.localIndex(j);
+            const auto local_j = node.localIndex(j);
 
             elementMatrix[local_i][local_j] += value * shapeValues[j];
             elementMatrix[local_j][local_i] += value * shapeValues[j];
@@ -115,10 +141,6 @@ namespace AMDiS
         }
       }
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
-    std::vector<Dune::FieldVector<double,1>> colShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/ZeroOrderTestTrialvec.hpp b/src/amdis/assembler/ZeroOrderTestTrialvec.hpp
index fbe2f3575f1ff39d7e940c500ca12b5fc22098cb..352cacfc0b58455043df285da8222924caba2127 100644
--- a/src/amdis/assembler/ZeroOrderTestTrialvec.hpp
+++ b/src/amdis/assembler/ZeroOrderTestTrialvec.hpp
@@ -19,28 +19,26 @@ namespace AMDiS
 
 
   /// zero-order operator \f$ \langle\psi, \mathbf{b}\cdot\Phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::test_trialvec, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::test_trialvec, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::test_trialvec, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Vector<typename GridFct::Range>, "Expression must be of vector type." );
 
   public:
-    GridFunctionOperator(tag::test_trialvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 0)
+    GridFunctionOperator(tag::test_trialvec, GridFct const& expr)
+      : Super(expr, 0)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE>,
-                                std::integral_constant<bool, sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isLeaf && ColNode::isPower,
         "RowNode must be Leaf-Node and ColNode must be a Power-Node.");
@@ -51,39 +49,45 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.finiteElement();
       auto const& colLocalFE = colNode.child(0).finiteElement();
 
-      auto* rowShapeValues = &rowShapeValues_;
-      auto* colShapeValues = (sameFE ? &rowShapeValues_ : &colShapeValues_);
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+      using RowRangeType = typename RowLocalBasisType::Traits::RangeType;
+      using ColRangeType = typename ColLocalBasisType::Traits::RangeType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      thread_local std::vector<RowRangeType> rowShapeValueBuffer;
+      thread_local std::vector<ColRangeType> colShapeValueBuffer;
+
+      const bool sameFE = std::is_same<decltype(rowLocalFE),decltype(colLocalFE)>::value;
+      auto* rowShapeValues = &rowShapeValueBuffer;
+      auto* colShapeValues = (sameFE ? &rowShapeValueBuffer : &colShapeValueBuffer);
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const auto b = Super::coefficient(local);
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValueBuffer);
         if (!sameFE)
-          colLocalFE.localBasis().evaluateFunction(local, colShapeValues_);
+          colLocalFE.localBasis().evaluateFunction(local, colShapeValueBuffer);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          const int local_i = rowNode.localIndex(i);
+          const auto local_i = rowNode.localIndex(i);
 
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            auto value = b * (factor * (*rowShapeValues)[i] * (*colShapeValues)[j]);
+            const auto value = b * (factor * (*rowShapeValues)[i] * (*colShapeValues)[j]);
 
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_kj = colNode.child(k).localIndex(j);
+              const auto local_kj = colNode.child(k).localIndex(j);
               elementMatrix[local_i][local_kj] += value[k];
             }
           }
         }
       }
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
-    std::vector<Dune::FieldVector<double,1>> colShapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/ZeroOrderTestvec.hpp b/src/amdis/assembler/ZeroOrderTestvec.hpp
index 49a5d40a90568993957cc2de0a16aa413178d96a..0a6c876c5d5f5a8fc6c26654e4e461fe50cb1ddd 100644
--- a/src/amdis/assembler/ZeroOrderTestvec.hpp
+++ b/src/amdis/assembler/ZeroOrderTestvec.hpp
@@ -19,25 +19,25 @@ namespace AMDiS
 
 
   /// zero-order vector-operator \f$ (\mathbf{b}\cdot\Psi) \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::testvec, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::testvec, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::testvec, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     static_assert( Category::Vector<typename GridFct::Range>, "Expression must be of vector type." );
 
   public:
-    GridFunctionOperator(tag::testvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 0)
+    GridFunctionOperator(tag::testvec, GridFct const& expr)
+      : Super(expr, 0)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementVector, class Node>
-    void calculateElementVector(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementVector& elementVector,
-                                Node const& node)
+    template <class Context, class Node, class ElementVector>
+    void getElementVector(Context const& context,
+                          Node const& node,
+                          ElementVector& elementVector)
     {
       static_assert(Node::isPower,
         "Operator can be applied to Power-Nodes only.");
@@ -46,28 +46,30 @@ namespace AMDiS
 
       auto const& localFE = node.child(0).finiteElement();
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeType = typename LocalBasisType::Traits::RangeType;
+
+      auto const& quad = this->getQuadratureRule(context.type(), node);
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const auto exprValue = Super::coefficient(local);
 
-        localFE.localBasis().evaluateFunction(local, shapeValues_);
+        thread_local std::vector<RangeType> shapeValues;
+        localFE.localBasis().evaluateFunction(local, shapeValues);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          auto value = exprValue * (factor * shapeValues_[i]);
+          const auto value = exprValue * (factor * shapeValues[i]);
           for (std::size_t k = 0; k < CHILDREN; ++k) {
-            const int local_ki = node.child(k).localIndex(i);
+            const auto local_ki = node.child(k).localIndex(i);
             elementVector[local_ki] += value[k];
           }
         }
       }
     }
-
-  private:
-    std::vector<Dune::FieldVector<double,1>> shapeValues_;
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/ZeroOrderTestvecTrial.hpp b/src/amdis/assembler/ZeroOrderTestvecTrial.hpp
index d6083d1ae911f0751411b9b10e7f7b8c4012dd46..f37c6aa46cc7bd46e7de3e1983c46b0c22c0b1b4 100644
--- a/src/amdis/assembler/ZeroOrderTestvecTrial.hpp
+++ b/src/amdis/assembler/ZeroOrderTestvecTrial.hpp
@@ -18,31 +18,19 @@ namespace AMDiS
 
 
   /// zero-order operator \f$ \langle\Psi, \mathbf{b}\,\phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::testvec_trial, GridFct, QuadCreator>
-      : public GridFunctionOperator<tag::test_trialvec, GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::testvec_trial, LocalContext, GridFct>
+      : public GridFunctionOperatorTransposed<GridFunctionOperator<tag::testvec_trial, LocalContext, GridFct>,
+                                              GridFunctionOperator<tag::test_trialvec, LocalContext, GridFct>>
   {
-    using Transposed = GridFunctionOperator<tag::test_trialvec, GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Transposed = GridFunctionOperator<tag::test_trialvec, LocalContext, GridFct>;
+    using Super = GridFunctionOperatorTransposed<Self, Transposed>;
 
   public:
-    GridFunctionOperator(tag::testvec_trial, GridFct const& expr, QuadCreator const& quadCreator)
-      : Transposed(tag::test_trialvec{}, expr, quadCreator)
+    GridFunctionOperator(tag::testvec_trial, GridFct const& expr)
+      : Super(tag::test_trialvec{}, expr)
     {}
-
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                std::integral_constant<bool, sameFE> flagSameFE,
-                                std::integral_constant<bool, sameNode> flagSameNode)
-    {
-      auto elementMatrixTransposed = trans(elementMatrix);
-      Transposed::calculateElementMatrix(
-        context, quad, elementMatrixTransposed, colNode, rowNode, flagSameFE, flagSameNode);
-    }
   };
 
   /** @} **/
diff --git a/src/amdis/assembler/ZeroOrderTestvecTrialvec.hpp b/src/amdis/assembler/ZeroOrderTestvecTrialvec.hpp
index 77a478e8685d749c9e69a451988fc83b585c0732..f8028777533a6387a55f8b1ef12cca1183f03b9b 100644
--- a/src/amdis/assembler/ZeroOrderTestvecTrialvec.hpp
+++ b/src/amdis/assembler/ZeroOrderTestvecTrialvec.hpp
@@ -19,30 +19,28 @@ namespace AMDiS
 
 
   /// zero-order operator \f$ \langle\Psi, c\,\Phi\rangle \f$, or \f$ \langle\Psi, A\,\Phi\rangle \f$
-  template <class GridFct, class QuadCreator>
-  class GridFunctionOperator<tag::testvec_trialvec, GridFct, QuadCreator>
-      : public GridFunctionOperatorBase<GridFct, QuadCreator>
+  template <class LocalContext, class GridFct>
+  class GridFunctionOperator<tag::testvec_trialvec, LocalContext, GridFct>
+      : public GridFunctionOperatorBase<GridFunctionOperator<tag::testvec_trialvec, LocalContext, GridFct>,
+                                        LocalContext, GridFct>
   {
-    using Super = GridFunctionOperatorBase<GridFct, QuadCreator>;
+    using Self = GridFunctionOperator;
+    using Super = GridFunctionOperatorBase<Self, LocalContext, GridFct>;
 
     using expr_value_type = typename GridFct::Range;
     static_assert( Category::Scalar<expr_value_type> || Category::Matrix<expr_value_type>,
       "Expression must be of scalar or matrix type." );
 
   public:
-    GridFunctionOperator(tag::testvec_trialvec, GridFct const& expr, QuadCreator const& quadCreator)
-      : Super(expr, quadCreator, 0)
+    GridFunctionOperator(tag::testvec_trialvec, GridFct const& expr)
+      : Super(expr, 0)
     {}
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calculateElementMatrix(Context const& context,
-                                QuadratureRule const& quad,
-                                ElementMatrix& elementMatrix,
-                                RowNode const& rowNode,
-                                ColNode const& colNode,
-                                bool_t<sameFE>,
-                                bool_t<sameNode>)
+    template <class Context, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrix(Context const& context,
+                          RowNode const& rowNode,
+                          ColNode const& colNode,
+                          ElementMatrix& elementMatrix)
     {
       static_assert(RowNode::isPower && ColNode::isPower,
         "Operator can be applied to Power-Nodes only.");
@@ -50,54 +48,65 @@ namespace AMDiS
       static_assert( (RowNode::CHILDREN == ColNode::CHILDREN), "" );
       // theoretically the restriction of the same nr of childs would not be necessary
 
+      const bool sameFE = std::is_same<FiniteElementType_t<RowNode>, FiniteElementType_t<ColNode>>::value;
+      const bool sameNode = rowNode.treeIndex() == colNode.treeIndex();
+
       using Category = ValueCategory_t<expr_value_type>;
-      calcElementMatrix(context, quad, elementMatrix, rowNode, colNode,
-        bool_<sameFE>,
-        bool_<sameNode>,
-        Category{});
+
+      auto const& quad = this->getQuadratureRule(context.type(), rowNode, colNode);
+      if (sameFE && sameNode && std::is_same<Category,tag::scalar>::value)
+        getElementMatrixOptimized(context, quad, rowNode, colNode, elementMatrix, Category{});
+      else
+        getElementMatrixStandard(context, quad, rowNode, colNode, elementMatrix, Category{});
     }
 
   protected: // specialization for different value-categories
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE>
-    void calcElementMatrix(Context const& context,
-                           QuadratureRule const& quad,
-                           ElementMatrix& elementMatrix,
-                           RowNode const& rowNode,
-                           ColNode const& colNode,
-                           bool_t<sameFE>,
-                           std::false_type /*sameNode*/,
-                           tag::scalar)
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixStandard(Context const& context,
+                                  QuadratureRule const& quad,
+                                  RowNode const& rowNode,
+                                  ColNode const& colNode,
+                                  ElementMatrix& elementMatrix,
+                                  tag::scalar)
     {
       static const std::size_t CHILDREN = RowNode::CHILDREN;
 
       auto const& rowLocalFE = rowNode.child(0).finiteElement();
       auto const& colLocalFE = colNode.child(0).finiteElement();
 
-      auto* rowShapeValues = &rowShapeValues_;
-      auto* colShapeValues = (sameFE ? &rowShapeValues_ : &colShapeValues_);
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+      using RowRangeType = typename RowLocalBasisType::Traits::RangeType;
+      using ColRangeType = typename ColLocalBasisType::Traits::RangeType;
+
+      thread_local std::vector<RowRangeType> rowShapeValueBuffer;
+      thread_local std::vector<ColRangeType> colShapeValueBuffer;
+
+      const bool sameFE = std::is_same<decltype(rowLocalFE),decltype(colLocalFE)>::value;
+      auto* rowShapeValues = &rowShapeValueBuffer;
+      auto* colShapeValues = (sameFE ? &rowShapeValueBuffer : &colShapeValueBuffer);
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValueBuffer);
         if (!sameFE)
-          colLocalFE.localBasis().evaluateFunction(local, colShapeValues_);
+          colLocalFE.localBasis().evaluateFunction(local, colShapeValueBuffer);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          double value = factor * (*rowShapeValues)[i];
+          const auto value = factor * (*rowShapeValues)[i];
 
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            double value0 = value * (*colShapeValues)[j];
+            const auto value0 = value * (*colShapeValues)[j];
 
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_ki = rowNode.child(k).localIndex(i);
-              const int local_kj = colNode.child(k).localIndex(j);
+              const auto local_ki = rowNode.child(k).localIndex(i);
+              const auto local_kj = colNode.child(k).localIndex(j);
 
               elementMatrix[local_ki][local_kj] += value0;
             }
@@ -107,46 +116,45 @@ namespace AMDiS
     }
 
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode>
-    void calcElementMatrix(Context const& context,
-                           QuadratureRule const& quad,
-                           ElementMatrix& elementMatrix,
-                           RowNode const& node,
-                           ColNode const& /*colNode*/,
-                           std::true_type /*sameFE*/,
-                           std::true_type /*sameNode*/,
-                           tag::scalar)
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   RowNode const& node,
+                                   ColNode const& /*colNode*/,
+                                   ElementMatrix& elementMatrix,
+                                   tag::scalar)
     {
       static const std::size_t CHILDREN = RowNode::CHILDREN;
 
       auto const& localFE = node.child(0).finiteElement();
 
-      auto& shapeValues = rowShapeValues_;
+      using LocalBasisType = typename std::decay_t<decltype(localFE)>::Traits::LocalBasisType;
+      using RangeType = typename LocalBasisType::Traits::RangeType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = Super::coefficient(local) * context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = Super::coefficient(local) * context.integrationElement(qp.position()) * qp.weight();
 
+        thread_local std::vector<RangeType> shapeValues;
         localFE.localBasis().evaluateFunction(local, shapeValues);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          double value = factor * shapeValues[i];
+          const auto value = factor * shapeValues[i];
 
           for (std::size_t k = 0; k < CHILDREN; ++k) {
-            const int local_ki = node.child(k).localIndex(i);
+            const auto local_ki = node.child(k).localIndex(i);
             elementMatrix[local_ki][local_ki] += value * shapeValues[i];
           }
 
           for (std::size_t j = i+1; j < localFE.size(); ++j) {
-            double value0 = value * shapeValues[j];
+            const auto value0 = value * shapeValues[j];
 
             for (std::size_t k = 0; k < CHILDREN; ++k) {
-              const int local_ki = node.child(k).localIndex(i);
-              const int local_kj = node.child(k).localIndex(j);
+              const auto local_ki = node.child(k).localIndex(i);
+              const auto local_kj = node.child(k).localIndex(j);
 
               elementMatrix[local_ki][local_kj] += value0;
               elementMatrix[local_kj][local_ki] += value0;
@@ -156,16 +164,13 @@ namespace AMDiS
       }
     }
 
-    template <class Context, class QuadratureRule,
-              class ElementMatrix, class RowNode, class ColNode, bool sameFE, bool sameNode>
-    void calcElementMatrix(Context const& context,
-                           QuadratureRule const& quad,
-                           ElementMatrix& elementMatrix,
-                           RowNode const& rowNode,
-                           ColNode const& colNode,
-                           bool_t<sameFE>,
-                           bool_t<sameNode>,
-                           tag::matrix)
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixStandard(Context const& context,
+                                  QuadratureRule const& quad,
+                                  RowNode const& rowNode,
+                                  ColNode const& colNode,
+                                  ElementMatrix& elementMatrix,
+                                  tag::matrix)
     {
       static const std::size_t CHILDREN = RowNode::CHILDREN;
       static_assert( std::is_same<expr_value_type, Dune::FieldMatrix<double, CHILDREN, CHILDREN>>::value, "" );
@@ -173,32 +178,41 @@ namespace AMDiS
       auto const& rowLocalFE = rowNode.child(0).finiteElement();
       auto const& colLocalFE = colNode.child(0).finiteElement();
 
-      auto* rowShapeValues = &rowShapeValues_;
-      auto* colShapeValues = (sameFE ? &rowShapeValues_ : &colShapeValues_);
+      using RowLocalBasisType = typename std::decay_t<decltype(rowLocalFE)>::Traits::LocalBasisType;
+      using ColLocalBasisType = typename std::decay_t<decltype(colLocalFE)>::Traits::LocalBasisType;
+      using RowRangeType = typename RowLocalBasisType::Traits::RangeType;
+      using ColRangeType = typename ColLocalBasisType::Traits::RangeType;
 
-      for (std::size_t iq = 0; iq < quad.size(); ++iq) {
+      thread_local std::vector<RowRangeType> rowShapeValueBuffer;
+      thread_local std::vector<ColRangeType> colShapeValueBuffer;
+
+      const bool sameFE = std::is_same<decltype(rowLocalFE),decltype(colLocalFE)>::value;
+      auto* rowShapeValues = &rowShapeValueBuffer;
+      auto* colShapeValues = (sameFE ? &rowShapeValueBuffer : &colShapeValueBuffer);
+
+      for (auto const& qp : quad) {
         // Position of the current quadrature point in the reference element
-        decltype(auto) local = context.position(quad[iq].position());
+        decltype(auto) local = context.local(qp.position());
 
         // The multiplicative factor in the integral transformation formula
-        double factor = context.integrationElement(quad[iq].position()) * quad[iq].weight();
+        const auto factor = context.integrationElement(qp.position()) * qp.weight();
         const Dune::FieldMatrix<double, CHILDREN, CHILDREN> exprValue = Super::coefficient(local);
 
-        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValues_);
+        rowLocalFE.localBasis().evaluateFunction(local, rowShapeValueBuffer);
         if (!sameFE)
-          colLocalFE.localBasis().evaluateFunction(local, colShapeValues_);
+          colLocalFE.localBasis().evaluateFunction(local, colShapeValueBuffer);
 
         for (std::size_t i = 0; i < rowLocalFE.size(); ++i) {
-          double value0 = factor * (*rowShapeValues)[i];
+          const auto value0 = factor * (*rowShapeValues)[i];
 
           for (std::size_t j = 0; j < colLocalFE.size(); ++j) {
-            double value = value0 * (*colShapeValues)[j];
-            auto mat = exprValue * value;
+            const auto value = value0 * (*colShapeValues)[j];
+            const auto mat = exprValue * value;
 
             for (std::size_t k0 = 0; k0 < CHILDREN; ++k0) {
-              const int local_ki = rowNode.child(k0).localIndex(i);
+              const auto local_ki = rowNode.child(k0).localIndex(i);
               for (std::size_t k1 = 0; k1 < CHILDREN; ++k1) {
-                const int local_kj = colNode.child(k1).localIndex(j);
+                const auto local_kj = colNode.child(k1).localIndex(j);
 
                 elementMatrix[local_ki][local_kj] += mat[k0][k1];
               }
@@ -208,9 +222,16 @@ namespace AMDiS
       }
     }
 
-  private:
-    std::vector<Dune::FieldVector<double,1>> rowShapeValues_;
-    std::vector<Dune::FieldVector<double,1>> colShapeValues_;
+    template <class Context, class QuadratureRule, class RowNode, class ColNode, class ElementMatrix>
+    void getElementMatrixOptimized(Context const& context,
+                                   QuadratureRule const& quad,
+                                   RowNode const& node,
+                                   ColNode const& /*colNode*/,
+                                   ElementMatrix& elementMatrix,
+                                   tag::matrix)
+    {
+      assert(false && "Not implemented.");
+    }
   };
 
   /** @} **/
diff --git a/src/amdis/common/FieldMatVec.hpp b/src/amdis/common/FieldMatVec.hpp
index b8fac3891e22d708fb6fba10616bd42cf935897d..3786be2b455a22901b47b05685c7db605397c1dd 100644
--- a/src/amdis/common/FieldMatVec.hpp
+++ b/src/amdis/common/FieldMatVec.hpp
@@ -217,6 +217,12 @@ namespace AMDiS
   template <class T, int N, int M>
   FieldVector<T,N> operator*(FieldMatrix<T,N,M> const& mat, FieldVector<T,M> const& vec);
 
+  template <class T, int N, int M>
+  FieldMatrix<T,N,M> operator*(FieldMatrix<T,N,M> mat, FieldVector<T,1> const& scalar);
+
+  template <class T, int N>
+  FieldMatrix<T,N,1> operator*(FieldMatrix<T,N,1> mat, FieldVector<T,1> const& scalar);
+
 
 
   template <class T, int M, int N, int L>
diff --git a/src/amdis/common/FieldMatVec.inc.hpp b/src/amdis/common/FieldMatVec.inc.hpp
index 8353b618d2725aef034be1640605f2c59a985dff..83254c16d7663a36a2df2d4135f127650eae0ebf 100644
--- a/src/amdis/common/FieldMatVec.inc.hpp
+++ b/src/amdis/common/FieldMatVec.inc.hpp
@@ -404,6 +404,18 @@ FieldVector<T,N> operator*(FieldMatrix<T,N,M> const& mat, FieldVector<T,M> const
   return Dune::FMatrixHelp::mult(mat, vec);
 }
 
+template <class T, int N, int M>
+FieldMatrix<T,N,M> operator*(FieldMatrix<T,N,M> mat, FieldVector<T,1> const& scalar)
+{
+  return mat *= scalar[0];
+}
+
+template <class T, int N>
+FieldMatrix<T,N,1> operator*(FieldMatrix<T,N,1> mat, FieldVector<T,1> const& scalar)
+{
+  return mat *= scalar[0];
+}
+
 
 
 template <class T, int M, int N, int L>
diff --git a/src/amdis/common/TupleUtility.hpp b/src/amdis/common/TupleUtility.hpp
index 202622fd4704e49da37365d8f22434fa7110a2cb..0a6f1c03b475fef208d86ded0960f5c212d24fd0 100644
--- a/src/amdis/common/TupleUtility.hpp
+++ b/src/amdis/common/TupleUtility.hpp
@@ -31,7 +31,7 @@ namespace AMDiS
       {
         static_assert(std::tuple_size<Tuple>::value == sizeof...(args),
             "Nr. of argument != tuple-size");
-        return {std::forward<Args>(args)...};
+        return Tuple{std::forward<Args>(args)...};
       }
     };
 
@@ -43,7 +43,7 @@ namespace AMDiS
       {
         static_assert(std::tuple_size<Tuple>::value == 0,
             "Construction of empty tuples with empty argument list only!");
-        return {};
+        return Tuple{};
       }
     };
 
diff --git a/src/amdis/common/Utility.hpp b/src/amdis/common/Utility.hpp
index dd897b88aeb70d0833899abd705c9c5909490c7a..08f9683e07d22ad3440048b47f44bff570b8d876 100644
--- a/src/amdis/common/Utility.hpp
+++ b/src/amdis/common/Utility.hpp
@@ -4,6 +4,12 @@
 #include <type_traits>
 #include <vector>
 
+#if AMDIS_HAS_CXX_CONSTEXPR_IF
+#define IF_CONSTEXPR if constexpr
+#else
+#define IF_CONSTEXPR if
+#endif
+
 namespace AMDiS
 {
   namespace Impl
@@ -46,6 +52,23 @@ namespace AMDiS
 
   // ---------------------------------------------------------------------------
 
+  // base template for tuple size, must implement a static value member
+  template <class TupleType>
+  struct TupleSize;
+
+  // utility constant returning the value of the tuple size
+  template <class TupleType>
+  constexpr std::size_t TupleSize_v = TupleSize<TupleType>::value;
+
+
+  // base template for retrieving the tuple element type, must implement the type member `type`
+  template <size_t I, class TupleType>
+  struct TupleElement;
+
+  // base template for retrieving the tuple element type
+  template <size_t I, class TupleType>
+  using TupleElement_t = typename TupleElement<I, TupleType>::type;
+
 
   /// A variadic type list
   template <class... Ts>
@@ -55,6 +78,23 @@ namespace AMDiS
   using Types_t = Types<std::decay_t<Ts>...>;
 
 
+  template <class... T>
+  struct TupleSize<Types<T...>>
+    : std::integral_constant<std::size_t, sizeof...(T)> {};
+
+  template <size_t I, class Head, class... Tail>
+  struct TupleElement<I, Types<Head, Tail...>>
+  {
+    using type = typename TupleElement<I-1, Types<Tail...>>::type;
+  };
+
+  template <class Head, class... Tail>
+  struct TupleElement<0, Types<Head, Tail...>>
+  {
+    using type = Head;
+  };
+
+
   /// Alias that indicates ownership of resources
   template <class T>
   using owner = T;
diff --git a/src/amdis/gridfunctions/AnalyticGridFunction.hpp b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
index 995a07c552c7f687524bd69e0d6f086edabc5536..c40e5af1b748b6f2821d84458814c8f3a43dc258 100644
--- a/src/amdis/gridfunctions/AnalyticGridFunction.hpp
+++ b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
@@ -25,9 +25,11 @@ namespace AMDiS
 
     using Geometry = typename LocalContext::Geometry;
 
+    enum { hasDerivative = true };
+
   public:
     AnalyticLocalFunction(Function const& fct)
-      : fct_(fct)
+      : fct_{fct}
     {}
 
     void bind(LocalContext const& element)
@@ -42,6 +44,7 @@ namespace AMDiS
 
     Range operator()(Domain const& local) const
     {
+      assert( bool(geometry_) );
       return fct_(geometry_.value().global(local));
     }
 
@@ -99,6 +102,8 @@ namespace AMDiS
     using Domain = typename EntitySet::GlobalCoordinate;
     using Range = std::decay_t<std::result_of_t<Function(Domain)>>;
 
+    enum { hasDerivative = true };
+
   private:
     using Element = typename EntitySet::Element;
     using LocalDomain = typename EntitySet::LocalCoordinate;
@@ -107,8 +112,8 @@ namespace AMDiS
   public:
     /// \brief Constructor. Stores the function `fct` and creates an `EntitySet`.
     AnalyticGridFunction(Function const& fct, GridView const& gridView)
-      : fct_(fct)
-      , entitySet_(gridView)
+      : fct_{fct}
+      , entitySet_{gridView}
     {}
 
     /// \brief Return the evaluated functor at global coordinates
@@ -118,12 +123,11 @@ namespace AMDiS
     }
 
     /// \brief Return the LocalFunction of the AnalyticGridFunction.
-    friend LocalFunction localFunction(AnalyticGridFunction const& gf)
+    LocalFunction localFunction() const
     {
-      return LocalFunction{gf.fct_};
+      return {fct_};
     }
 
-
     EntitySet const& entitySet() const
     {
       return entitySet_;
@@ -138,6 +142,12 @@ namespace AMDiS
   };
 
 
+  template <class F, class GV>
+  auto localFunction(AnalyticGridFunction<F,GV> const& gf)
+  {
+    return gf.localFunction();
+  }
+
   /// \brief Return a GridFunction representing the derivative of a functor.
   // [expects: Functor f has free function derivative(f)]
   template <class F, class GV>
diff --git a/src/amdis/gridfunctions/ConstantGridFunction.hpp b/src/amdis/gridfunctions/ConstantGridFunction.hpp
index d139d0f51a1890d94fb5f012d69bd4dc85fec736..275da96fbd7e114572c8ef65427a7a9e708cb23d 100644
--- a/src/amdis/gridfunctions/ConstantGridFunction.hpp
+++ b/src/amdis/gridfunctions/ConstantGridFunction.hpp
@@ -27,6 +27,8 @@ namespace AMDiS
 
     using Geometry = typename LocalContext::Geometry;
 
+    enum { hasDerivative = true };
+
   public:
     ConstantLocalFunction(T const& value)
       : value_(value)
@@ -41,8 +43,15 @@ namespace AMDiS
       return value_;
     }
 
-    /// \relates ConstantLocalFunction
-    friend int order(ConstantLocalFunction const& /*lf*/)
+    auto derivative() const
+    {
+      using RawSignature = typename Dune::Functions::SignatureTraits<R(D)>::RawSignature;
+      using DerivativeRange = typename Dune::Functions::DefaultDerivativeTraits<RawSignature>::Range;
+      DerivativeRange diff(0);
+      return ConstantLocalFunction<DerivativeRange(D),LocalContext,DerivativeRange>{diff};
+    }
+
+    int order() const
     {
       return 0;
     }
@@ -55,12 +64,17 @@ namespace AMDiS
   template <class R, class D, class LocalContext, class T>
   auto derivative(ConstantLocalFunction<R(D), LocalContext, T> const& lf)
   {
-    using RawSignature = typename Dune::Functions::SignatureTraits<R(D)>::RawSignature;
-    using DerivativeRange = typename Dune::Functions::DefaultDerivativeTraits<RawSignature>::Range;
-    DerivativeRange diff(0);
-    return ConstantLocalFunction<DerivativeRange(D),LocalContext,DerivativeRange>{diff};
+    return lf.derivative();
   }
 
+  /// \relates ConstantLocalFunction
+  template <class R, class D, class LocalContext, class T>
+  int order(ConstantLocalFunction<R(D), LocalContext, T> const& lf)
+  {
+    return lf.order();
+  }
+
+
 
   /**
     * \addtogroup GridFunctions
@@ -85,6 +99,8 @@ namespace AMDiS
     using LocalDomain = typename EntitySet::LocalCoordinate;
     using Range = Underlying_t<T>;
 
+    enum { hasDerivative = false };
+
   public:
     using LocalFunction = ConstantLocalFunction<Range(LocalDomain), Element, T>;
 
@@ -106,7 +122,10 @@ namespace AMDiS
       return entitySet_;
     }
 
-    T const& value() const { return value_; }
+    LocalFunction localFunction() const
+    {
+      return {value_};
+    }
 
   private:
     T value_;
@@ -115,9 +134,9 @@ namespace AMDiS
 
   /// Return the LocalFunction of the \ref ConstantGridFunction. \relates ConstantGridFunction
   template <class T, class GV>
-  typename ConstantGridFunction<T,GV>::LocalFunction localFunction(ConstantGridFunction<T,GV> const& gf)
+  auto localFunction(ConstantGridFunction<T,GV> const& gf)
   {
-    return {gf.value()};
+    return gf.localFunction();
   }
 
   /** @} **/
diff --git a/src/amdis/gridfunctions/DOFVectorView.hpp b/src/amdis/gridfunctions/DOFVectorView.hpp
index f0a5f9376131a55dc31ed1eae9f937674ab706b4..e71139e6cf220778070202bbcc276c99a885aec1 100644
--- a/src/amdis/gridfunctions/DOFVectorView.hpp
+++ b/src/amdis/gridfunctions/DOFVectorView.hpp
@@ -49,6 +49,7 @@ namespace AMDiS
     template <class Block>
     using Flat = Dune::Functions::FlatVectorBackend<Block>;
 
+    enum { hasDerivative = false };
 
   public: // a local view on the gradients
 
@@ -59,6 +60,8 @@ namespace AMDiS
       using Domain = LocalDomain;
       using Range = DerivativeRange;
 
+      enum { hasDerivative = false };
+
     private:
       using LocalBasisView = typename GlobalBasis::LocalView;
       using LocalIndexSet = typename GlobalBasis::LocalIndexSet;
@@ -135,6 +138,8 @@ namespace AMDiS
       using Domain = typename DOFVectorConstView::LocalDomain;
       using Range = typename DOFVectorConstView::Range;
 
+      enum { hasDerivative = true };
+
     private:
       using LocalBasisView = typename GlobalBasis::LocalView;
       using LocalIndexSet = typename GlobalBasis::LocalIndexSet;
@@ -297,6 +302,13 @@ namespace AMDiS
       return *this;
     }
 
+    template <class Expr>
+    DOFVectorMutableView& operator<<(Expr&& expr)
+    {
+      return interpolate(expr);
+    }
+
+
     /// Return the mutable DOFVector
     DOFVector<Traits>& coefficients() { return *mutableDofVector_; }
 
diff --git a/src/amdis/gridfunctions/DerivativeGridFunction.hpp b/src/amdis/gridfunctions/DerivativeGridFunction.hpp
index 5a7e621f2cc890ff5959c2259cfcd722329e432b..e4c0adc7f64304342260e00b5f0aa3d5f4bee75c 100644
--- a/src/amdis/gridfunctions/DerivativeGridFunction.hpp
+++ b/src/amdis/gridfunctions/DerivativeGridFunction.hpp
@@ -32,6 +32,8 @@ namespace AMDiS
     using DerivativeTraits = Dune::Functions::DefaultDerivativeTraits<RawSignature>;
     using LocalFunction = std::decay_t<decltype(derivative(localFunction(std::declval<GridFunction>())))>;
 
+    enum { hasDerivative = false };
+
   public:
     /// The Range of the derivative of the GridFunction
     using Range = typename DerivativeTraits::Range;
@@ -45,7 +47,7 @@ namespace AMDiS
   public:
     /// Constructor. Stores a copy of gridFct.
     explicit DerivativeGridFunction(GridFunction const& gridFct)
-      : gridFct_(gridFct)
+      : gridFct_{gridFct}
     {
       static_assert(isValidRange<DerivativeTraits>(), "Derivative of GridFunction not defined");
     }
@@ -77,7 +79,7 @@ namespace AMDiS
 #ifndef DOXYGEN
   template <class GridFct,
             class LocalFct = decltype(localFunction(std::declval<GridFct>())),
-    REQUIRES(not Concepts::HasDerivative<GridFct>)>
+    REQUIRES(not GridFct::hasDerivative)>
   auto derivative(GridFct const& gridFct)
   {
     static_assert(Concepts::HasDerivative<LocalFct>, "derivative(LocalFunction) not defined!");
diff --git a/src/amdis/gridfunctions/FunctorGridFunction.hpp b/src/amdis/gridfunctions/FunctorGridFunction.hpp
index c7905acd403c91df98836a5e006694d51f56b8e9..8b12ab2546c0e7580fc5067164c363560494bcf7 100644
--- a/src/amdis/gridfunctions/FunctorGridFunction.hpp
+++ b/src/amdis/gridfunctions/FunctorGridFunction.hpp
@@ -34,9 +34,11 @@ namespace AMDiS
   } // end namespace Impl
 
 
+  // forward declaration
   template <class Signatur, class Functor, class... LocalFunctions>
   class FunctorLocalFunction;
 
+  // implementation
   template <class R, class D, class Functor, class... LocalFunctions>
   class FunctorLocalFunction<R(D), Functor, LocalFunctions...>
   {
@@ -44,12 +46,28 @@ namespace AMDiS
     using Range = R;
     using Domain = D;
 
+    enum { hasDerivative = true };
+
+    template <class LocalFct>
+    struct LocalFunctionWrapper
+    {
+      template <class GridFct>
+      LocalFunctionWrapper(GridFct const& gridFct)
+        : localFct_{localFunction(gridFct)}
+      {}
+
+      LocalFct const& operator*() const { return localFct_; }
+      LocalFct      & operator*()       { return localFct_; }
+
+      LocalFct localFct_;
+    };
+
   public:
     /// Constructor. Stores copies of the functor and localFunction(gridfunction)s.
-    template <class... LocalFcts>
-    FunctorLocalFunction(Functor const& fct, LocalFcts&&... localFcts)
-      : fct_(fct)
-      , localFcts_(std::forward<LocalFcts>(localFcts)...)
+    template <class... GridFcts>
+    FunctorLocalFunction(Functor const& fct, GridFcts&&... gridFcts)
+      : fct_{fct}
+      , localFcts_{std::forward<GridFcts>(gridFcts)...}
     {}
 
     /// Calls \ref bind for all localFunctions
@@ -57,7 +75,7 @@ namespace AMDiS
     void bind(Element const& element)
     {
       forEach(localFcts_, [&](auto& localFct) {
-        localFct.bind(element);
+        (*localFct).bind(element);
       });
     }
 
@@ -65,22 +83,15 @@ namespace AMDiS
     void unbind()
     {
       forEach(localFcts_, [&](auto& localFct) {
-        localFct.unbind();
+        (*localFct).unbind();
       });
     }
 
     /// Applies the functor \ref fct_ to the evaluated localFunctions
     Range operator()(Domain const& x) const
     {
-      return eval([&x](auto const& localFct) { return localFct(x); },
-        MakeSeq_t<sizeof...(LocalFunctions)>{});
-    }
-
-  private:
-    template <class Op, std::size_t... I>
-    auto eval(Op op, Indices<I...>) const
-    {
-      return fct_(op(std::get<I>(localFcts_))...);
+      using Dune::Std::apply;
+      return apply([&](auto&&... localFct) { return fct_((*localFct)(x)...); }, localFcts_);
     }
 
   public:
@@ -90,14 +101,14 @@ namespace AMDiS
       return fct_;
     }
 
-    std::tuple<LocalFunctions...> const& localFcts() const
+    auto const& localFcts() const
     {
       return localFcts_;
     }
 
   private:
     Functor fct_;
-    std::tuple<LocalFunctions...> localFcts_;
+    std::tuple<LocalFunctionWrapper<LocalFunctions>...> localFcts_;
   };
 
   // Derivative of the LocalFunction of a FunctorGridFunction, utilizing
@@ -109,21 +120,24 @@ namespace AMDiS
     REQUIRES(Concepts::HasPartial<F>)>
   auto derivative(FunctorLocalFunction<Sig,F,LFs...> const& lf)
   {
-    auto index_seq = std::make_index_sequence<sizeof...(LFs)>{};
+    auto index_seq = std::index_sequence_for<LFs...>{};
 
     // d_i(f)[lgfs...] * lgfs_i
     auto term_i = [&](auto const _i)
     {
-      auto di_f = Dune::Std::apply([&](auto const&... lgfs) {
-        return makeFunctorGridFunction(partial(lf.fct(), _i), lgfs...);
+      using Dune::Std::apply;
+      auto di_f = apply([&](auto const&... lgfs) {
+        return makeFunctorGridFunction(partial(lf.fct(), _i), (*lgfs)...);
       }, lf.localFcts());
 
-      auto const& lgfs_i = std::get<decltype(_i)::value>(lf.localFcts());
+      using std::get;
+      auto const& lgfs_i = *get<decltype(_i)::value>(lf.localFcts());
       return makeFunctorGridFunction(Operation::Multiplies{}, di_f, derivative(lgfs_i));
     };
 
-    // sum_i [ d_i(f)[lgfs...] * derivative(lgfs_i) ]
-    auto gridFct = Dune::Std::apply([&](auto const... _i)
+    // sum_i [ d_i(f)[lgfs...] * derivative(lgfs_i)
+    using Dune::Std::apply;
+    auto gridFct = apply([&](auto const... _i)
     {
       return makeFunctorGridFunction(Operation::Plus{}, term_i(_i)...);
     }, index_seq);
@@ -139,7 +153,8 @@ namespace AMDiS
              && all_of_v<Concepts::HasOrder<LFs>...>)>
   int order(FunctorLocalFunction<Sig,F,LFs...> const& lf)
   {
-    return Dune::Std::apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(lgfs)...); },
+    using Dune::Std::apply;
+    return apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(*lgfs)...); },
       lf.localFcts());
   }
 
@@ -173,6 +188,8 @@ namespace AMDiS
     /// The set of entities this grid-function binds to
     using EntitySet = typename Impl::EntitySetType<GridFunctions...>::type;
 
+    enum { hasDerivative = false };
+
   private:
     template <class GridFct>
     using LocalFct = std::decay_t<decltype(localFunction(std::declval<GridFct>()))>;
@@ -186,31 +203,28 @@ namespace AMDiS
     /// Constructor. Stores copies of the functor and gridfunctions.
     template <class... GridFcts>
     explicit FunctorGridFunction(Functor const& fct, GridFcts&&... gridFcts)
-      : fct_(fct)
-      , gridFcts_(std::forward<GridFcts>(gridFcts)...)
+      : fct_{fct}
+      , gridFcts_{std::forward<GridFcts>(gridFcts)...}
     {}
 
     /// Applies the functor to the evaluated gridfunctions
     Range operator()(Domain const& x) const
     {
-      return eval(fct_, [&x](auto const& gridFct) { return gridFct(x); },
-        MakeSeq_t<sizeof...(GridFunctions)>{});
+      using Dune::Std::apply;
+      return apply([&](auto&&... gridFct) { return fct_(gridFct(x)...); }, gridFcts_);
     }
 
     /// Return the stored \ref EntitySet of the first GridFunction
     EntitySet const& entitySet() const
     {
-      return std::get<0>(gridFcts_).entitySet();
+      using std::get;
+      return get<0>(gridFcts_).entitySet();
     }
 
-    auto const& fct() const { return fct_; }
-    auto const& gridFcts() const { return gridFcts_; }
-
-  private:
-    template <class Outer, class Inner, std::size_t... I>
-    auto eval(Outer outer, Inner inner, Indices<I...>) const
+    LocalFunction localFunction() const
     {
-      return outer(inner(std::get<I>(gridFcts_))...);
+      using Dune::Std::apply;
+      return apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_);
     }
 
   private:
@@ -223,16 +237,10 @@ namespace AMDiS
   template <class F, class... GFs>
   auto localFunction(FunctorGridFunction<F,GFs...> const& gf)
   {
-    return Dune::Std::apply([&gf](auto const&... gridFcts)
-    {
-      using LocalFunction = typename FunctorGridFunction<F,GFs...>::LocalFunction;
-      return LocalFunction{gf.fct(), localFunction(gridFcts)...};
-    },
-    gf.gridFcts());
+    return gf.localFunction();
   }
 
 
-#ifndef DOXYGEN
   // Generator function for FunctorGridFunction expressions
   template <class Functor, class... GridFcts>
   auto makeFunctorGridFunction(Functor const& f, GridFcts const&... gridFcts)
@@ -245,7 +253,7 @@ namespace AMDiS
   }
 
   // PreGridFunction related to FunctorGridFunction.
-  template <class Functor, class... GridFunctions>
+  template <class Functor, class... PreGridFunctions>
   struct FunctorPreGridFunction
   {
     using Self = FunctorPreGridFunction;
@@ -258,28 +266,27 @@ namespace AMDiS
         return Dune::Std::apply([&](auto const&... pgf) {
           return makeFunctorGridFunction(self.fct_,
             makeGridFunction(pgf, gridView)...);
-        }, self.gridFcts_);
+        }, self.preGridFcts_);
       }
     };
 
-    template <class... GridFcts>
-    explicit FunctorPreGridFunction(Functor const& fct, GridFcts&&... gridFcts)
-      : fct_(fct)
-      , gridFcts_(std::forward<GridFcts>(gridFcts)...)
+    template <class... PreGridFcts>
+    explicit FunctorPreGridFunction(Functor const& fct, PreGridFcts&&... pgfs)
+      : fct_{fct}
+      , preGridFcts_{std::forward<PreGridFcts>(pgfs)...}
     {}
 
   private:
     Functor fct_;
-    std::tuple<GridFunctions...> gridFcts_;
+    std::tuple<PreGridFunctions...> preGridFcts_;
   };
 
   namespace Traits
   {
-    template <class Functor, class... GridFunctions>
-    struct IsPreGridFunction<FunctorPreGridFunction<Functor, GridFunctions...>>
+    template <class Functor, class... PreGridFcts>
+    struct IsPreGridFunction<FunctorPreGridFunction<Functor, PreGridFcts...>>
       : std::true_type {};
   }
-#endif
 
 
   /// \brief Generator function for FunctorGridFunction. \relates FunctorGridFunction
@@ -291,10 +298,10 @@ namespace AMDiS
    * - `invokeAtQP([](double u, auto const& x) { return u + x[0]; }, 1.0, X());`
    * - `invokeAtQP(Operation::Plus{}, X(0), X(1));`
    **/
-  template <class Functor, class... GridFcts>
-  auto invokeAtQP(Functor const& f, GridFcts&&... gridFcts)
+  template <class Functor, class... PreGridFcts>
+  auto invokeAtQP(Functor const& f, PreGridFcts&&... gridFcts)
   {
-    return FunctorPreGridFunction<Functor, std::decay_t<GridFcts>...>{f, std::forward<GridFcts>(gridFcts)...};
+    return FunctorPreGridFunction<Functor, std::decay_t<PreGridFcts>...>{f, std::forward<PreGridFcts>(gridFcts)...};
   }
 
   /** @} **/
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 73701a09ed01b65438f4cf3c7bab0ad55c500955..b5eb3aaba4cf03f3d7803773612b3456642963a3 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -4,7 +4,7 @@ dune_add_test(SOURCES AdaptInfoTest.cpp
 
 dune_add_test(SOURCES ClonablePtrTest.cpp
   LINK_LIBRARIES amdis)
-  
+
 dune_add_test(SOURCES ConceptsTest.cpp
   LINK_LIBRARIES amdis)
 
diff --git a/test/TupleUtilityTest.cpp b/test/TupleUtilityTest.cpp
index 4f40c2c374d07aa36432f8b08f376e5037f310ac..9d99c3baf104c2e3e7e2025c1c505677dd2d6eeb 100644
--- a/test/TupleUtilityTest.cpp
+++ b/test/TupleUtilityTest.cpp
@@ -14,13 +14,13 @@ int main()
   using TupleInt = std::tuple<int,int>;
   using Tuple2 = std::tuple<TupleDouble,TupleInt>;
 
-  Tuple1 u = {1.3, 2};
+  Tuple1 u{1.3, 2};
   auto v = constructTuple<Tuple1>(1.5);
   auto w = foldTuples<Tuple2>(u,v);
 
-  AMDIS_TEST(u == Tuple1({1.3, 2}));
-  AMDIS_TEST(v == Tuple1({1.5, 1}));
-  AMDIS_TEST(w == Tuple2( {{1.3, 1.5}, {2, 1}} ));
+  AMDIS_TEST((u == Tuple1{1.3, 2}));
+  AMDIS_TEST((v == Tuple1{1.5, 1}));
+  AMDIS_TEST((w == Tuple2{TupleDouble{1.3, 1.5}, TupleDouble{2, 1}} ));
 
   return report_errors();
 }
\ No newline at end of file