From 01aefb507a185dffcab51b14d8922f576861d508 Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Mon, 2 Jul 2018 14:37:17 +0200
Subject: [PATCH] Removed tuple implementation and used wrapper instead

---
 src/amdis/Assembler.hpp                       |   6 +-
 src/amdis/FiniteElementSpaces.hpp             | 133 ----------
 src/amdis/GridFunctionOperator.hpp            |  25 +-
 src/amdis/LocalAssemblerBase.hpp              |  85 +-----
 src/amdis/LocalAssemblerList.hpp              |  96 +++++++
 src/amdis/LocalOperator.hpp                   |  23 +-
 .../gridfunctions/AnalyticGridFunction.hpp    |   9 +-
 src/amdis/gridfunctions/DOFVectorView.hpp     |   7 +
 .../gridfunctions/DerivativeGridFunction.hpp  |  15 +-
 .../gridfunctions/FunctorGridFunction.hpp     |  95 ++++---
 src/amdis/utility/Tuple.hpp                   | 247 ------------------
 test/CMakeLists.txt                           |   3 -
 test/TupleTest.cpp                            |  51 ----
 13 files changed, 207 insertions(+), 588 deletions(-)
 delete mode 100644 src/amdis/FiniteElementSpaces.hpp
 create mode 100644 src/amdis/LocalAssemblerList.hpp
 delete mode 100644 src/amdis/utility/Tuple.hpp
 delete mode 100644 test/TupleTest.cpp

diff --git a/src/amdis/Assembler.hpp b/src/amdis/Assembler.hpp
index c5f6ab4e..be425fc9 100644
--- a/src/amdis/Assembler.hpp
+++ b/src/amdis/Assembler.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/FiniteElementSpaces.hpp b/src/amdis/FiniteElementSpaces.hpp
deleted file mode 100644
index 10775960..00000000
--- 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 1cda525f..70a12642 100644
--- a/src/amdis/GridFunctionOperator.hpp
+++ b/src/amdis/GridFunctionOperator.hpp
@@ -16,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
@@ -24,6 +25,7 @@ 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.
@@ -36,21 +38,26 @@ namespace AMDiS
   class GridFunctionOperatorBase
       : public LocalOperator<Derived, LocalContext>
   {
+    /// The type of the localFunction associated with the GridFunction
     using LocalFunction = decltype(localFunction(std::declval<GridFunction>()));
 
+    /// 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 `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, int termOrder)
       : gridFct_(gridFct)
@@ -78,7 +85,8 @@ 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_impl(Element const& element, Geometry const& geometry)
     {
@@ -93,6 +101,7 @@ namespace AMDiS
       localFct_.unbind();
     }
 
+    /// Create a quadrature factory from a PreQuadratureFactory, e.g. class derived from \ref QuadratureFactory
     template <class PreQuadFactory>
     void setQuadFactory(PreQuadFactory const& pre)
     {
@@ -107,7 +116,7 @@ namespace AMDiS
       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>
     auto const& getQuadratureRule(Dune::GeometryType type, Nodes const&... nodes) const
@@ -148,23 +157,27 @@ namespace AMDiS
       : transposedOp_(std::forward<Args>(args)...)
     {}
 
+    /// Redirects the bind call top the transposed operator
     template <class Element, class Geometry>
     void bind_impl(Element const& element, Geometry const& geometry)
     {
       transposedOp_.bind_impl(element, geometry);
     }
 
+    /// Redirects the unbind call top the transposed operator
     void unbind_impl()
     {
       transposedOp_.unbind_impl();
     }
 
+    /// Redirects the setQuadFactory call top the transposed operator
     template <class PreQuadFactory>
     void setQuadFactory(PreQuadFactory const& pre)
     {
       transposedOp_.setQuadFactory(pre);
     }
 
+    /// 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,
diff --git a/src/amdis/LocalAssemblerBase.hpp b/src/amdis/LocalAssemblerBase.hpp
index 50892963..f6320729 100644
--- a/src/amdis/LocalAssemblerBase.hpp
+++ b/src/amdis/LocalAssemblerBase.hpp
@@ -1,13 +1,10 @@
 #pragma once
 
-#include <list>
-#include <memory>
 #include <type_traits>
 
 #include <amdis/ContextGeometry.hpp>
-#include <amdis/common/ConceptsBase.hpp>
+// #include <amdis/common/ConceptsBase.hpp>
 #include <amdis/common/TypeDefs.hpp>
-#include <amdis/utility/TreeData.hpp>
 
 namespace AMDiS
 {
@@ -16,24 +13,28 @@ namespace AMDiS
   class LocalAssemblerBase
   {
   public:
-
+    /// The codim=0 grid entity
     using Element = typename Impl::ContextTypes<LocalContext>::Entity;
+    /// The geometry of the \ref Element
     using Geometry = typename Element::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)
@@ -42,74 +43,4 @@ namespace AMDiS
                           ElementMatrixVector& elementMatrixVector) = 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 doAssemble(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>;
-  };
-
-
-  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 00000000..e4b1dc79
--- /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
index 87d2f3d3..5509510a 100644
--- a/src/amdis/LocalOperator.hpp
+++ b/src/amdis/LocalOperator.hpp
@@ -18,15 +18,18 @@ namespace AMDiS
   /**
    * The CRTP Base class for local operators.
    *
-   * \tparam Derived  The class that derives from this base class
+   * \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
@@ -112,19 +115,19 @@ namespace AMDiS
 
     // 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)
+    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)
+    void getElementVector(Context const& /*context*/,
+                          Node const& /*node*/,
+                          ElementVector& /*elementVector*/)
     {
       error_exit("Needs to be implemented by derived class!");
     }
@@ -186,14 +189,14 @@ namespace AMDiS
   };
 
 
-  /// Generate an \ref GridFunctionOperator from a PreOperator.
+  /// 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 \ref GridFunctionOperator from a PreOperator.
+  /// 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*/)
   {
diff --git a/src/amdis/gridfunctions/AnalyticGridFunction.hpp b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
index 055bfff1..40bd3918 100644
--- a/src/amdis/gridfunctions/AnalyticGridFunction.hpp
+++ b/src/amdis/gridfunctions/AnalyticGridFunction.hpp
@@ -27,7 +27,7 @@ namespace AMDiS
 
   public:
     AnalyticLocalFunction(Function const& fct)
-      : fct_(fct)
+      : fct_{fct}
     {}
 
     void bind(LocalContext const& element)
@@ -42,7 +42,7 @@ namespace AMDiS
 
     Range operator()(Domain const& local) const
     {
-      assert(geometry_.has_value());
+      assert( bool(geometry_) );
       return fct_(geometry_.value().global(local));
     }
 
@@ -108,8 +108,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
@@ -124,7 +124,6 @@ namespace AMDiS
       return {fct_};
     }
 
-
     EntitySet const& entitySet() const
     {
       return entitySet_;
diff --git a/src/amdis/gridfunctions/DOFVectorView.hpp b/src/amdis/gridfunctions/DOFVectorView.hpp
index f0a5f937..91ddcb18 100644
--- a/src/amdis/gridfunctions/DOFVectorView.hpp
+++ b/src/amdis/gridfunctions/DOFVectorView.hpp
@@ -297,6 +297,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 5a7e621f..87fccfb8 100644
--- a/src/amdis/gridfunctions/DerivativeGridFunction.hpp
+++ b/src/amdis/gridfunctions/DerivativeGridFunction.hpp
@@ -45,7 +45,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");
     }
@@ -58,9 +58,9 @@ namespace AMDiS
     }
 
     /// Return the derivative-localFunction of the GridFunction.
-    friend LocalFunction localFunction(DerivativeGridFunction const& gf)
+    LocalFunction localFunction() const
     {
-      return derivative(localFunction(gf.gridFct_));
+      return derivative(localFunction(gridFct_));
     }
 
     /// Return the \ref EntitySet of the \ref GridFunction.
@@ -74,7 +74,13 @@ namespace AMDiS
   };
 
 
-#ifndef DOXYGEN
+  template <class GF>
+  auto localFunction(DerivativeGridFunction<GF> const& gf)
+  {
+    return gf.localFunction();
+  }
+
+
   template <class GridFct,
             class LocalFct = decltype(localFunction(std::declval<GridFct>())),
     REQUIRES(not Concepts::HasDerivative<GridFct>)>
@@ -85,6 +91,7 @@ namespace AMDiS
   }
 
 
+#ifndef DOXYGEN
   template <class Expr>
   struct DerivativePreGridFunction
   {
diff --git a/src/amdis/gridfunctions/FunctorGridFunction.hpp b/src/amdis/gridfunctions/FunctorGridFunction.hpp
index 26653e29..f3158053 100644
--- a/src/amdis/gridfunctions/FunctorGridFunction.hpp
+++ b/src/amdis/gridfunctions/FunctorGridFunction.hpp
@@ -47,12 +47,26 @@ namespace AMDiS
     using Range = R;
     using Domain = D;
 
+    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... GridFcts>
     FunctorLocalFunction(Functor const& fct, GridFcts&&... gridFcts)
-      : fct_(fct)
-      , localFcts_{tag::mapped_arg{}, [](auto const& gf) { return localFunction(gf); }, std::forward<GridFcts>(gridFcts)...}
+      : fct_{fct}
+      , localFcts_{std::forward<GridFcts>(gridFcts)...}
     {}
 
     /// Calls \ref bind for all localFunctions
@@ -60,7 +74,7 @@ namespace AMDiS
     void bind(Element const& element)
     {
       forEach(localFcts_, [&](auto& localFct) {
-        localFct.bind(element);
+        (*localFct).bind(element);
       });
     }
 
@@ -68,22 +82,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(get<I>(localFcts_))...);
+      using Dune::Std::apply;
+      return apply([&](auto&&... localFct) { return fct_(localFct(x)...); }, localFcts_);
     }
 
   public:
@@ -93,14 +100,14 @@ namespace AMDiS
       return fct_;
     }
 
-    Tuple<LocalFunctions...> const& localFcts() const
+    auto const& localFcts() const
     {
       return localFcts_;
     }
 
   private:
     Functor fct_;
-    Tuple<LocalFunctions...> localFcts_;
+    std::tuple<LocalFunctionWrapper<LocalFunctions>...> localFcts_;
   };
 
   // Derivative of the LocalFunction of a FunctorGridFunction, utilizing
@@ -119,11 +126,11 @@ namespace AMDiS
     {
       using Dune::Std::apply;
       auto di_f = apply([&](auto const&... lgfs) {
-        return makeFunctorGridFunction(partial(lf.fct(), _i), lgfs...);
+        return makeFunctorGridFunction(partial(lf.fct(), _i), (*lgfs)...);
       }, lf.localFcts());
 
       using std::get;
-      auto const& lgfs_i = get<decltype(_i)::value>(lf.localFcts());
+      auto const& lgfs_i = *get<decltype(_i)::value>(lf.localFcts());
       return makeFunctorGridFunction(Operation::Multiplies{}, di_f, derivative(lgfs_i));
     };
 
@@ -146,7 +153,7 @@ namespace AMDiS
   int order(FunctorLocalFunction<Sig,F,LFs...> const& lf)
   {
     using Dune::Std::apply;
-    return apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(lgfs)...); },
+    return apply([&lf](auto const&... lgfs) { return order(lf.fct(), order(*lgfs)...); },
       lf.localFcts());
   }
 
@@ -193,15 +200,15 @@ 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
@@ -211,15 +218,10 @@ namespace AMDiS
       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
     {
-      using std::get;
-      return outer(inner(get<I>(gridFcts_))...);
+      using Dune::Std::apply;
+      return apply([&](auto const&... gridFcts) { return LocalFunction{fct_, gridFcts...}; }, gridFcts_);
     }
 
   private:
@@ -232,16 +234,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(), gridFcts...};
-    },
-    gf.gridFcts());
+    return gt.localFunction();
   }
 
 
-#ifndef DOXYGEN
   // Generator function for FunctorGridFunction expressions
   template <class Functor, class... GridFcts>
   auto makeFunctorGridFunction(Functor const& f, GridFcts const&... gridFcts)
@@ -254,7 +250,7 @@ namespace AMDiS
   }
 
   // PreGridFunction related to FunctorGridFunction.
-  template <class Functor, class... GridFunctions>
+  template <class Functor, class... PreGridFunctions>
   struct FunctorPreGridFunction
   {
     using Self = FunctorPreGridFunction;
@@ -267,28 +263,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
@@ -300,10 +295,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/src/amdis/utility/Tuple.hpp b/src/amdis/utility/Tuple.hpp
deleted file mode 100644
index e6b946de..00000000
--- a/src/amdis/utility/Tuple.hpp
+++ /dev/null
@@ -1,247 +0,0 @@
-#pragma once
-
-#include <utility>
-
-#include <amdis/common/Mpl.hpp>
-#include <amdis/common/Utility.hpp>
-
-#include <dune/common/typetraits.hh>
-
-namespace AMDiS
-{
-  // inspired by Sasha Goldshtein's implementation,
-  // see http://blogs.microsoft.co.il/sasha/2015/01/12/implementing-tuple-part-1
-
-  namespace tag
-  {
-    struct mapped_arg {};
-  }
-
-  namespace Impl
-  {
-    template <std::size_t, class T>
-    struct TupleEntry
-    {
-      TupleEntry() = default;
-
-      explicit TupleEntry(T const& value) : value_(value) {}
-      explicit TupleEntry(T&& value) : value_(std::move(value)) {}
-
-      // create value through a map of arguments
-      template <class Map, class... Args>
-      TupleEntry(tag::mapped_arg, Map&& map, Args&&... args)
-        : value_(map(std::forward<Args>(args)...))
-      {}
-
-      T value_;
-    };
-
-    template <class Sequences, class... Types>
-    struct TupleImpl;
-
-    template <class T>
-    struct IsTupleImpl : std::false_type {};
-
-    template <class Sequences, class... Types>
-    struct IsTupleImpl<TupleImpl<Sequences,Types...>> : std::true_type {};
-
-
-    template <std::size_t... Indices, class... Types>
-    struct TupleImpl<std::index_sequence<Indices...>, Types...>
-      : TupleEntry<Indices, Types>...
-    {
-      TupleImpl() = default;
-
-      // constructor from sequence of types, disabling this for copy and move constructor
-      template <class... OtherTypes,
-        std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0,
-        std::enable_if_t<none_of_v<IsTupleImpl<std::decay_t<OtherTypes>>::value...>, int> = 0>
-      explicit TupleImpl(OtherTypes&&... other)
-        : TupleEntry<Indices, Types>{std::forward<OtherTypes>(other)}...
-      {}
-
-      // constructor using a map to build the elements
-      template <class Map, class... OtherTypes,
-        std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0>
-      TupleImpl(tag::mapped_arg, Map&& map, OtherTypes&&... other)
-        : TupleEntry<Indices, Types>{tag::mapped_arg{}, std::forward<Map>(map), std::forward<OtherTypes>(other)}...
-      {}
-    };
-
-  } // end namespace Impl
-
-  /// \brief Implementation of tuple, that allows mapped construction
-  template <class... Types>
-  class Tuple
-    : public Impl::TupleImpl<std::index_sequence_for<Types...>, Types...>
-  {
-    using Super = Impl::TupleImpl<std::index_sequence_for<Types...>, Types...>;
-
-  public:
-    // some default constructors
-    Tuple() = default;
-    Tuple(Tuple const&) = default;
-    Tuple(Tuple&&) = default;
-    Tuple& operator=(Tuple const&) = default;
-    Tuple& operator=(Tuple&&) = default;
-
-    /// Construct from types different from Types, but convertible
-    template <class... OtherTypes,
-      std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0>
-    explicit Tuple(OtherTypes&&... other)
-      : Super{std::forward<OtherTypes>(other)...}
-    {}
-
-    /// Constructor from tuple of possibly other types
-    template <class... OtherTypes,
-      std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0>
-    explicit Tuple(Tuple<OtherTypes...> const& that)
-      : Super{that}
-    {}
-
-    /// Constructor from tuple of possibly other types
-    template <class... OtherTypes,
-      std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0>
-    explicit Tuple(Tuple<OtherTypes...>&& that)
-      : Super{std::move(that)}
-    {}
-
-    /// Constructor using a map to build the elements
-    template <class Map, class... OtherTypes,
-      std::enable_if_t<(sizeof...(OtherTypes) == sizeof...(Types)), int> = 0>
-    Tuple(tag::mapped_arg, Map&& map, OtherTypes&&... other)
-      : Super{tag::mapped_arg{}, std::forward<Map>(map), std::forward<OtherTypes>(other)...}
-    {}
-
-    /// Get the I'th tuple element by reference
-    template <std::size_t I>
-    auto& operator[](std::integral_constant<std::size_t,I>)
-    {
-      Impl::TupleEntry<I, TupleElement_t<I, AMDiS::Types<Types...>>>& base = *this;
-      return base.value_;
-    }
-
-    /// Get the I'th tuple element by const reference
-    template <std::size_t I>
-    auto const& operator[](std::integral_constant<std::size_t,I>) const
-    {
-      Impl::TupleEntry<I, TupleElement_t<I, AMDiS::Types<Types...>>> const& base = *this;
-      return base.value_;
-    }
-
-    /// Return the number of elements in this tuple
-    constexpr std::size_t size() const
-    {
-      return sizeof...(Types);
-    }
-  };
-
-
-  /// Get the I'th tuple element type
-  template <std::size_t I, class... T>
-  struct TupleElement<I, Tuple<T...>>
-    : TupleElement<I, Types<T...>> {};
-
-
-  /// Get the size of the tuple
-  template <class... T>
-  struct TupleSize<Tuple<T...>>
-    : std::integral_constant<std::size_t, sizeof...(T)> {};
-
-
-  namespace Impl
-  {
-    /// Get the I'th tuple element by reference
-    template <std::size_t I, class... T>
-    auto& get(Tuple<T...>& tuple)
-    {
-      Impl::TupleEntry<I, TupleElement_t<I, Types<T...>>>& base = tuple;
-      return base.value_;
-    }
-
-    /// Get the I'th tuple element by const reference
-    template <std::size_t I, class... T>
-    auto const& get(Tuple<T...> const& tuple)
-    {
-      Impl::TupleEntry<I, TupleElement_t<I, Types<T...>>> const& base = tuple;
-      return base.value_;
-    }
-
-    /// Get the I'th tuple element by rvalue reference
-    template <std::size_t I, class... T>
-    auto&& get(Tuple<T...>&& tuple)
-    {
-      Impl::TupleEntry<I, TupleElement_t<I, Types<T...>>>&& base = tuple;
-      return std::move(base.value_);
-    }
-
-    template<class F, class TupleType, std::size_t... i>
-    decltype(auto) applyImpl(F&& f, TupleType&& args, std::index_sequence<i...>)
-    {
-      return f(get<i>(args)...);
-    }
-
-    template <class F, class... T>
-    decltype(auto) apply(F&& f, Tuple<T...> const& args)
-    {
-      auto indices = std::index_sequence_for<T...>{};
-      return applyImpl(std::forward<F>(f), args, indices);
-    }
-
-    template <class F, class... T>
-    decltype(auto) apply(F&& f, Tuple<T...>& args)
-    {
-      auto indices = std::index_sequence_for<T...>{};
-      return applyImpl(std::forward<F>(f), args, indices);
-    }
-
-  } // end namespace Impl
-
-  // inject get(Tuple) into namespace AMDiS by `using` directive
-  using Impl::get;
-
-  // inject apply(F,Tuple) into namespace AMDiS by `using` directive
-  using Impl::apply;
-
-
-  template <class... Types>
-  Tuple<Types&&...> forwardAsTuple(Types&&... elements)
-  {
-    return Tuple<Types&&...>{std::forward<Types>(elements)...};
-  }
-
-  template <class... Types>
-  Tuple<Types&...> tie(Types&... elements)
-  {
-    return Tuple<Types&...>{elements...};
-  }
-
-} // end namespace AMDiS
-
-namespace std
-{
-  template <class... T>
-  struct tuple_size<AMDiS::Tuple<T...>>
-    : AMDiS::TupleSize<AMDiS::Tuple<T...>> {};
-
-  template <std::size_t I, class... T>
-  struct tuple_element<I, AMDiS::Tuple<T...>>
-    : AMDiS::TupleElement<I, AMDiS::Tuple<T...>> {};
-
-  // inject get(AMDiS::Tuple) into namespace std by `using` directive
-  using AMDiS::Impl::get;
-
-  // inject apply(F,AMDiS::Tuple) into namespace std by `using` directive
-  using AMDiS::Impl::apply;
-
-} // end namespace std
-
-
-namespace Dune
-{
-  namespace Std
-  {
-    using AMDiS::Impl::apply;
-
-  } // end namespace Std
-} // end namespace Dune
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d17857e7..b5eb3aab 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -38,6 +38,3 @@ dune_add_test(SOURCES TreeDataTest.cpp
 
 dune_add_test(SOURCES TupleUtilityTest.cpp
   LINK_LIBRARIES amdis)
-
-dune_add_test(SOURCES TupleTest.cpp
-  LINK_LIBRARIES amdis)
diff --git a/test/TupleTest.cpp b/test/TupleTest.cpp
deleted file mode 100644
index 10c39b28..00000000
--- a/test/TupleTest.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <tuple>
-#include <iostream>
-
-#include <amdis/utility/Tuple.hpp>
-#include <dune/common/hybridutilities.hh>
-#include <dune/common/std/apply.hh>
-
-#include "Tests.hpp"
-
-using namespace AMDiS;
-
-struct B {};
-
-struct A
-{
-  A() = delete;
-  A(A const&) = delete;
-  A(A&&) = delete;
-
-  A(B,B) {};
-};
-
-struct MakeA
-{
-  A operator()(B const& b) const
-  {
-    return {b,b};
-  }
-};
-
-
-int main()
-{
-  Tuple<double,int> u{1.3, 2};
-  Tuple<double,int> v{1, 2};
-
-  Tuple<int, double> t1;
-  get<0>(t1) = 42;
-
-  Tuple<int> t2(3);
-  Tuple<int> t3(t1);
-
-  // construct a tuple of non-copyable and non-movable types
-  Tuple<A> t4(tag::mapped_arg{}, MakeA{}, B{});
-
-  Dune::Hybrid::forEach(u, [](auto value) { std::cout << value << "\n"; });
-
-  Dune::Std::apply([](auto... values) { return std::make_tuple(values...); }, u);
-
-  return report_errors();
-}
\ No newline at end of file
-- 
GitLab