From a2ee6796c21e65304ad381c1bd84d7d777518c64 Mon Sep 17 00:00:00 2001
From: TiKeil <keil.menden@web.de>
Date: Wed, 18 Jul 2018 14:07:35 +0200
Subject: [PATCH] [combined] rename combined.hh -> combined-grid-functions

---
 .../functions/base/combined-grid-functions.hh | 521 +++++++++++++++++
 dune/xt/functions/base/combined.hh            | 532 ------------------
 2 files changed, 521 insertions(+), 532 deletions(-)
 create mode 100644 dune/xt/functions/base/combined-grid-functions.hh
 delete mode 100644 dune/xt/functions/base/combined.hh

diff --git a/dune/xt/functions/base/combined-grid-functions.hh b/dune/xt/functions/base/combined-grid-functions.hh
new file mode 100644
index 000000000..197c048f9
--- /dev/null
+++ b/dune/xt/functions/base/combined-grid-functions.hh
@@ -0,0 +1,521 @@
+// This file is part of the dune-xt-functions project:
+//   https://github.com/dune-community/dune-xt-functions
+// Copyright 2009-2018 dune-xt-functions developers and contributors. All rights
+// reserved.
+// License: Dual licensed as BSD 2-Clause License
+// (http://opensource.org/licenses/BSD-2-Clause)
+//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
+//          with "runtime exception" (http://www.dune-project.org/license.html)
+// Authors:
+//   Felix Schindler (2013 - 2017)
+//   Rene Milk       (2014 - 2018)
+//   Tobias Leibner  (2014, 2017)
+
+#ifndef DUNE_XT_FUNCTIONS_BASE_COMBINED_GRID_FUNCTIONS_HH
+#define DUNE_XT_FUNCTIONS_BASE_COMBINED_GRID_FUNCTIONS_HH
+
+#include <dune/xt/functions/base/combined-functions.hh>
+#include <dune/xt/functions/interfaces/function.hh>
+#include <dune/xt/functions/interfaces/grid-function.hh>
+
+namespace Dune {
+namespace XT {
+namespace Functions {
+namespace internal {
+
+/**
+ *
+ * todo: this can probably be done more intelligent
+ */
+
+enum class Combinations { difference, sum, product }; // enum class Combinations
+
+/**
+ * \brief Helper class defining types of combined functions, if available.
+ *
+ * \note Most likely you do not want to use this class directly, but Combined.
+ */
+template <class LeftType, class RightType, Combinations comb>
+class SelectCombinedGridFunction {
+  static_assert(is_grid_function<LeftType>::value, "");
+  static_assert(is_grid_function<RightType>::value, "");
+
+public:
+  using E = typename LeftType::ElementType;
+  using D = typename LeftType::DomainFieldType;
+  static const size_t d = LeftType::domain_dim;
+  using R = typename LeftType::RangeFieldType;
+
+private:
+  static_assert(std::is_same<typename RightType::ElementType, E>::value,
+                "Types do not match!");
+  static_assert(std::is_same<typename RightType::DomainFieldType, D>::value,
+                "Types do not match!");
+  static_assert(RightType::domain_dim == d, "Dimensions do not match!");
+  static_assert(std::is_same<typename RightType::RangeFieldType, R>::value,
+                "Types do not match!");
+
+  template <class L, class R> class Choose {
+    template <size_t rL, size_t rR, size_t rCL, size_t rcR, Combinations cc,
+              bool anything = true>
+    class Dimension {
+      static_assert(!anything,
+                    "No combination for these dimensions available!");
+    };
+
+    template <size_t r_in, size_t rC_in, bool anything>
+    class Dimension<r_in, r_in, rC_in, rC_in, Combinations::difference,
+                    anything> {
+    public:
+      static const size_t r = r_in;
+      static const size_t rC = rC_in;
+    };
+
+    template <size_t r_in, size_t rC_in, bool anything>
+    class Dimension<r_in, r_in, rC_in, rC_in, Combinations::sum, anything> {
+    public:
+      static const size_t r = r_in;
+      static const size_t rC = rC_in;
+    };
+
+    template <size_t r_in, size_t rC_in, bool anything>
+    class Dimension<1, r_in, 1, rC_in, Combinations::product, anything> {
+    public:
+      static const size_t r = r_in;
+      static const size_t rC = rC_in;
+    };
+
+  public:
+    static const size_t r =
+        Dimension<L::range_dim, R::range_dim, L::range_dim_cols,
+                  R::range_dim_cols, comb>::r;
+    static const size_t rC =
+        Dimension<L::range_dim, R::range_dim, L::range_dim_cols,
+                  R::range_dim_cols, comb>::rC;
+  }; // class Choose
+
+public:
+  static const size_t r = Choose<LeftType, RightType>::r;
+  static const size_t rC = Choose<LeftType, RightType>::rC;
+
+  using LeftLocalFunctionType = typename LeftType::LocalFunctionType;
+  using RightLocalFunctionType = typename RightType::LocalFunctionType;
+  using DomainType = typename ElementFunctionInterface<E, r, rC, R>::DomainType;
+  using RangeType = typename RightType::LocalFunctionType::RangeType;
+  using ScalarRangeType = typename LeftType::LocalFunctionType::RangeType;
+  using DerivativeRangeType =
+      typename ElementFunctionInterface<E, r, rC, R>::DerivativeRangeType;
+  using DerivativeRangeReturnType =
+      typename ElementFunctionInterface<E, r, rC, R>::DerivativeRangeReturnType;
+
+private:
+  template <Combinations cc, bool anything = true> class Call {
+    static_assert(!anything, "Nothing available for these combinations!");
+  }; // class Call
+
+  template <bool anything> class Call<Combinations::difference, anything> {
+  public:
+    static std::string type() { return "difference"; }
+
+    static size_t order(const size_t left_order, const size_t right_order) {
+      return std::max(left_order, right_order);
+    }
+
+    static RangeType evaluate(const LeftLocalFunctionType &left_local,
+                              const RightLocalFunctionType &right_local,
+                              const DomainType &point_in_reference_element,
+                              const Common::Parameter &param) {
+      return left_local.evaluate(point_in_reference_element, param) -
+             right_local.evaluate(point_in_reference_element, param);
+    }
+
+    static DerivativeRangeReturnType
+    jacobian(const LeftLocalFunctionType &left_local,
+             const RightLocalFunctionType &right_local,
+             const DomainType &point_in_reference_element,
+             const Common::Parameter &param) {
+      return left_local.jacobian(point_in_reference_element, param) -
+             right_local.jacobian(point_in_reference_element, param);
+    } // ... jacobian(...)
+  };  // class Call< ..., difference >
+
+  template <bool anything> class Call<Combinations::sum, anything> {
+  public:
+    static std::string type() { return "sum"; }
+
+    static size_t order(const size_t left_order, const size_t right_order) {
+      return std::max(left_order, right_order);
+    }
+
+    static RangeType evaluate(const LeftLocalFunctionType &left_local,
+                              const RightLocalFunctionType &right_local,
+                              const DomainType &point_in_reference_element,
+                              const Common::Parameter &param) {
+      return left_local.evaluate(point_in_reference_element, param) +
+             right_local.evaluate(point_in_reference_element, param);
+    } // ... evaluate(...)
+
+    static DerivativeRangeReturnType
+    jacobian(const LeftLocalFunctionType &left_local,
+             const RightLocalFunctionType &right_local,
+             const DomainType &point_in_reference_element,
+             const Common::Parameter &param) {
+      return left_local.jacobian(point_in_reference_element, param) +
+             right_local.jacobian(point_in_reference_element, param);
+    } // ... jacobian(...)
+  };  // class Call< ..., sum >
+
+  // left only scalar atm
+  template <bool anything> class Call<Combinations::product, anything> {
+  public:
+    static std::string type() { return "product"; }
+
+    static size_t order(const size_t left_order, const size_t right_order) {
+      return left_order + right_order;
+    }
+
+    static RangeType evaluate(const LeftLocalFunctionType &left_local,
+                              const RightLocalFunctionType &right_local,
+                              const DomainType &point_in_reference_element,
+                              const Common::Parameter &param) {
+      ScalarRangeType left_eval =
+          left_local.evaluate(point_in_reference_element, param);
+      RangeType right_eval =
+          right_local.evaluate(point_in_reference_element, param);
+      if (left_eval.size() != 1)
+        DUNE_THROW(NotImplemented, "Only available for scalar left type!");
+      right_eval *= left_eval[0];
+      return right_eval;
+    } // ... evaluate(...)
+
+    static DerivativeRangeReturnType
+    jacobian(const LeftLocalFunctionType & /*left_local*/,
+             const RightLocalFunctionType & /*right_local*/,
+             const DomainType & /*point_in_reference_element*/,
+             const Common::Parameter & /*param*/) {
+      DUNE_THROW(NotImplemented, "If you need this, implement it!");
+      return DerivativeRangeReturnType();
+    }
+  }; // class Call< ..., product >
+
+public:
+  static std::string type() { return Call<comb>::type(); }
+
+  static size_t order(const size_t left_order, const size_t right_order) {
+    return Call<comb>::order(left_order, right_order);
+  }
+
+  static RangeType evaluate(const LeftLocalFunctionType &left_local,
+                            const RightLocalFunctionType &right_local,
+                            const DomainType &point_in_reference_element,
+                            const Common::Parameter &param) {
+    return Call<comb>::evaluate(left_local, right_local,
+                                point_in_reference_element, param);
+  }
+
+  static DerivativeRangeReturnType
+  jacobian(const LeftLocalFunctionType &left_local,
+           const RightLocalFunctionType &right_local,
+           const DomainType &point_in_reference_element,
+           const Common::Parameter &param) {
+    return Call<comb>::jacobian(left_local, right_local,
+                                point_in_reference_element, param);
+  }
+}; // class SelectCombinedGridFunction
+
+/**
+ * \brief Generic combined local function.
+ *
+ * \note Most likely you do not want to use this class directly, but Combined.
+ */
+template <class LeftType, class RightType, Combinations type>
+class CombinedLocalFunction
+    : public ElementFunctionInterface<
+          typename SelectCombinedGridFunction<LeftType, RightType, type>::E,
+          SelectCombinedGridFunction<LeftType, RightType, type>::r,
+          SelectCombinedGridFunction<LeftType, RightType, type>::rC,
+          typename SelectCombinedGridFunction<LeftType, RightType, type>::R> {
+  using BaseType = ElementFunctionInterface<
+      typename SelectCombinedGridFunction<LeftType, RightType, type>::E,
+      SelectCombinedGridFunction<LeftType, RightType, type>::r,
+      SelectCombinedGridFunction<LeftType, RightType, type>::rC,
+      typename SelectCombinedGridFunction<LeftType, RightType, type>::R>;
+
+  using Select = SelectCombinedGridFunction<LeftType, RightType, type>;
+
+public:
+  using typename BaseType::ElementType;
+  using typename BaseType::DomainType;
+  using typename BaseType::RangeType;
+  using typename BaseType::DerivativeRangeType;
+  using typename BaseType::RangeReturnType;
+  using typename BaseType::DerivativeRangeReturnType;
+
+  CombinedLocalFunction(const LeftType &left, const RightType &right)
+      : BaseType(), left_local_(left.local_function()),
+        right_local_(right.local_function()) {}
+
+protected:
+  void post_bind(const ElementType &element) override final {
+    left_local_->bind(element);
+    right_local_->bind(element);
+  }
+
+public:
+  int order(const XT::Common::Parameter &param = {}) const override final {
+    return Select::order(left_local_->order(param), right_local_->order(param));
+  }
+
+  RangeReturnType
+  evaluate(const DomainType &point_in_reference_element,
+           const Common::Parameter &param = {}) const override final {
+    return Select::evaluate(*left_local_, *right_local_,
+                            point_in_reference_element, param);
+  }
+
+  DerivativeRangeReturnType
+  jacobian(const DomainType &point_in_reference_element,
+           const Common::Parameter &param = {}) const override final {
+    return Select::jacobian(*left_local_, *right_local_,
+                            point_in_reference_element, param);
+  }
+
+private:
+  std::unique_ptr<typename LeftType::LocalFunctionType> left_local_;
+  std::unique_ptr<typename RightType::LocalFunctionType> right_local_;
+}; // class CombinedLocalFunction
+
+/**
+ * \brief Generic combined function.
+ *
+ *        This class combines two given functions of type LeftType and RightType
+using the given combination
+ *        Combinations. This class (and any derived class, like Difference, Sum
+or Product) can be used in two ways:
+ *        - You can pass references of the left and right operand to this class.
+This is done for instance when calling
+ *          operator+, operator- or operator* on any function deriving from
+GridFunctionInterface:
+\code
+using IndicatorType = Functions::IndicatorFunction< ..., double>;
+IndicatorType one( ... );
+IndicatorType two( ... );
+// the following code
+auto difference = one - two;
+// is equivalent to
+Difference< IndicatorType, IndicatorType > difference(one, two);
+// and
+internal::Combined< IndicatorType, IndicatorType, Combinations::difference >
+difference(one, tow);
+\endcode
+ *          In this situation you are responsible to ensure that the arguments
+given are valid throughout the lifetime
+ *          of this class. The following will lead to a segfault:
+\code
+using IndicatorType = Functions::IndicatorFunction< ..., double >;
+
+Difference< IndicatorType, IndicatorType > stupid_difference()
+{
+  IndicatorType one( ... );
+  IndicatorType two( ... );
+  return one - two;
+}
+\endcode
+ *        - You can pass shared_ptr of the left and right operands to this
+class. In this case the following is valid:
+\code
+using IndicatorType = Functions::IndicatorFunction< ..., double >;
+
+Difference< IndicatorType, IndicatorType > stupid_difference()
+{
+  auto one = std::make_shared< IndicatorType >(1);
+  auto two = std::make_shared< IndicatorType >(2);
+  return Difference< IndicatorType, IndicatorType >(one, two)
+}
+\endcode
+ *
+ * \note  Most likely you do not want to use this class diretly, but one of
+Difference, Sum or Product.
+ */
+template <class LeftType, class RightType, Combinations comb>
+class CombinedGridFunction
+    : public GridFunctionInterface<
+          typename SelectCombinedGridFunction<LeftType, RightType, comb>::E,
+          SelectCombinedGridFunction<LeftType, RightType, comb>::r,
+          SelectCombinedGridFunction<LeftType, RightType, comb>::rC,
+          typename SelectCombinedGridFunction<LeftType, RightType, comb>::R> {
+  using BaseType = GridFunctionInterface<
+      typename SelectCombinedGridFunction<LeftType, RightType, comb>::E,
+      SelectCombinedGridFunction<LeftType, RightType, comb>::r,
+      SelectCombinedGridFunction<LeftType, RightType, comb>::rC,
+      typename SelectCombinedGridFunction<LeftType, RightType, comb>::R>;
+
+  using LeftStorageType = Common::ConstStorageProvider<LeftType>;
+  using RightStorageType = Common::ConstStorageProvider<RightType>;
+  using ThisType = CombinedGridFunction<LeftType, RightType, comb>;
+
+public:
+  using ElementType = typename BaseType::ElementType;
+  using LocalFunctionType = typename BaseType::LocalFunctionType;
+
+  CombinedGridFunction(const LeftType &left, const RightType &right,
+                       const std::string nm = "")
+      : left_(Common::make_unique<LeftStorageType>(left)),
+        right_(Common::make_unique<RightStorageType>(right)),
+        name_(nm.empty()
+                  ? SelectCombinedGridFunction<LeftType, RightType,
+                                               comb>::type() +
+                        " of '" + left.name() + "' and '" + right.name() + "'"
+                  : nm) {}
+
+  CombinedGridFunction(const std::shared_ptr<const LeftType> left,
+                       const std::shared_ptr<const RightType> right,
+                       const std::string nm = "")
+      : left_(Common::make_unique<LeftStorageType>(left)),
+        right_(Common::make_unique<RightStorageType>(right)),
+        name_(nm.empty()
+                  ? SelectCombinedGridFunction<LeftType, RightType,
+                                               comb>::type() +
+                        " of '" + left_->access().name() + "' and '" +
+                        right_->access().name() + "'"
+                  : nm) {}
+
+  CombinedGridFunction(ThisType &&source) = default;
+
+  CombinedGridFunction(const ThisType &other) = delete;
+
+  ThisType &operator=(const ThisType &other) = delete;
+
+  ThisType &operator=(ThisType &&other) = delete;
+
+  std::unique_ptr<LocalFunctionType> local_function() const override final {
+    using RealLocalFunctionType =
+        CombinedLocalFunction<LeftType, RightType, comb>;
+    assert(left_);
+    assert(right_);
+    return Common::make_unique<RealLocalFunctionType>(left_->access(),
+                                                      right_->access());
+  } // ... local_function(...)
+
+  std::string type() const override final {
+    return SelectCombinedGridFunction<LeftType, RightType, comb>::type() +
+           " of '" + left_->access().type() + "' and '" +
+           right_->access().type() + "'";
+  } // ... type(...)
+
+  std::string name() const override final { return name_; }
+
+private:
+  std::unique_ptr<const LeftStorageType> left_;
+  std::unique_ptr<const RightStorageType> right_;
+  const std::string name_;
+}; // class CombinedGridFunction
+
+} // namespace internal
+
+/**
+ * \brief Function representing the difference between two functions.
+ *
+ * \see internal::CombinedGridFunction
+ */
+template <class MinuendType, class SubtrahendType>
+class DifferenceGridFunction
+    : public internal::CombinedGridFunction<
+          MinuendType, SubtrahendType, internal::Combinations::difference> {
+  using BaseType =
+      internal::CombinedGridFunction<MinuendType, SubtrahendType,
+                                     internal::Combinations::difference>;
+
+public:
+  template <class... Args>
+  explicit DifferenceGridFunction(Args &&... args)
+      : BaseType(std::forward<Args>(args)...) {}
+}; // class DifferenceGridFunction
+
+/**
+ * \brief Function representing the sum of two functions.
+ *
+ * \see internal::CombinedGridFunction
+ */
+template <class LeftSummandType, class RightSummandType>
+class SumGridFunction
+    : public internal::CombinedGridFunction<LeftSummandType, RightSummandType,
+                                            internal::Combinations::sum> {
+  using BaseType =
+      internal::CombinedGridFunction<LeftSummandType, RightSummandType,
+                                     internal::Combinations::sum>;
+
+public:
+  template <class... Args>
+  explicit SumGridFunction(Args &&... args)
+      : BaseType(std::forward<Args>(args)...) {}
+}; // class SumGridFunction
+
+/**
+ * \brief Function representing the product of two functions.
+ *
+ * \see internal::CombinedGridFunction
+ */
+template <class LeftSummandType, class RightSummandType>
+class ProductGridFunction
+    : public internal::CombinedGridFunction<LeftSummandType, RightSummandType,
+                                            internal::Combinations::product> {
+  using BaseType =
+      internal::CombinedGridFunction<LeftSummandType, RightSummandType,
+                                     internal::Combinations::product>;
+
+public:
+  template <class... Args>
+  explicit ProductGridFunction(Args &&... args)
+      : BaseType(std::forward<Args>(args)...) {}
+}; // class ProductGridFunction
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<DifferenceGridFunction<T1, T2>>
+make_difference(const T1 &left, const T2 &right, Args &&... args) {
+  return std::make_shared<DifferenceGridFunction<T1, T2>>(
+      left, right, std::forward<Args>(args)...);
+}
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<DifferenceGridFunction<T1, T2>>
+make_difference(std::shared_ptr<T1> left, std::shared_ptr<T2> right,
+                Args &&... args) {
+  return std::make_shared<DifferenceGridFunction<T1, T2>>(
+      left, right, std::forward<Args>(args)...);
+}
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<SumGridFunction<T1, T2>>
+make_sum(const T1 &left, const T2 &right, Args &&... args) {
+  return std::make_shared<SumGridFunction<T1, T2>>(left, right,
+                                                   std::forward<Args>(args)...);
+}
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<SumGridFunction<T1, T2>>
+make_sum(std::shared_ptr<T1> left, std::shared_ptr<T2> right, Args &&... args) {
+  return std::make_shared<SumGridFunction<T1, T2>>(left, right,
+                                                   std::forward<Args>(args)...);
+}
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<ProductGridFunction<T1, T2>>
+make_product(const T1 &left, const T2 &right, Args &&... args) {
+  return std::make_shared<ProductGridFunction<T1, T2>>(
+      left, right, std::forward<Args>(args)...);
+}
+
+template <class T1, class T2, class... Args>
+std::shared_ptr<ProductGridFunction<T1, T2>>
+make_product(std::shared_ptr<T1> left, std::shared_ptr<T2> right,
+             Args &&... args) {
+  return std::make_shared<ProductGridFunction<T1, T2>>(
+      left, right, std::forward<Args>(args)...);
+}
+
+} // namespace Functions
+} // namespace XT
+} // namespace Dune
+
+#endif // DUNE_XT_FUNCTIONS_BASE_COMBINED_HH
diff --git a/dune/xt/functions/base/combined.hh b/dune/xt/functions/base/combined.hh
deleted file mode 100644
index da8f6f848..000000000
--- a/dune/xt/functions/base/combined.hh
+++ /dev/null
@@ -1,532 +0,0 @@
-// This file is part of the dune-xt-functions project:
-//   https://github.com/dune-community/dune-xt-functions
-// Copyright 2009-2018 dune-xt-functions developers and contributors. All rights reserved.
-// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
-//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
-//          with "runtime exception" (http://www.dune-project.org/license.html)
-// Authors:
-//   Felix Schindler (2013 - 2017)
-//   Rene Milk       (2014 - 2018)
-//   Tobias Leibner  (2014, 2017)
-
-#ifndef DUNE_XT_FUNCTIONS_BASE_COMBINED_HH
-#define DUNE_XT_FUNCTIONS_BASE_COMBINED_HH
-
-#include <dune/xt/functions/interfaces/grid-function.hh>
-#include <dune/xt/functions/interfaces/function.hh>
-
-namespace Dune {
-namespace XT {
-namespace Functions {
-namespace internal {
-
-
-enum class Combination
-{
-  difference,
-  sum,
-  product
-}; // enum class Combination
-
-
-/**
- * \brief Helper class defining types of combined functions, if available.
- *
- * \note Most likely you do not want to use this class directly, but Combined.
- */
-template <class LeftType, class RightType, Combination comb>
-class SelectCombined
-{
-  static_assert(is_grid_function<LeftType>::value, "");
-  static_assert(is_grid_function<RightType>::value, "");
-
-public:
-  using E = typename LeftType::ElementType;
-  using D = typename LeftType::DomainFieldType;
-  static const size_t d = LeftType::domain_dim;
-  using R = typename LeftType::RangeFieldType;
-
-private:
-  static_assert(std::is_same<typename RightType::ElementType, E>::value, "Types do not match!");
-  static_assert(std::is_same<typename RightType::DomainFieldType, D>::value, "Types do not match!");
-  static_assert(RightType::domain_dim == d, "Dimensions do not match!");
-  static_assert(std::is_same<typename RightType::RangeFieldType, R>::value, "Types do not match!");
-
-  template <class L, class R>
-  class Choose
-  {
-    template <size_t rL, size_t rR, size_t rCL, size_t rcR, Combination cc, bool anything = true>
-    class Dimension
-    {
-      static_assert(!anything, "No combination for these dimensions available!");
-    };
-
-    template <size_t r_in, size_t rC_in, bool anything>
-    class Dimension<r_in, r_in, rC_in, rC_in, Combination::difference, anything>
-    {
-    public:
-      static const size_t r = r_in;
-      static const size_t rC = rC_in;
-    };
-
-    template <size_t r_in, size_t rC_in, bool anything>
-    class Dimension<r_in, r_in, rC_in, rC_in, Combination::sum, anything>
-    {
-    public:
-      static const size_t r = r_in;
-      static const size_t rC = rC_in;
-    };
-
-    template <size_t r_in, size_t rC_in, bool anything>
-    class Dimension<1, r_in, 1, rC_in, Combination::product, anything>
-    {
-    public:
-      static const size_t r = r_in;
-      static const size_t rC = rC_in;
-    };
-
-  public:
-    static const size_t r = Dimension<L::range_dim, R::range_dim, L::range_dim_cols, R::range_dim_cols, comb>::r;
-    static const size_t rC = Dimension<L::range_dim, R::range_dim, L::range_dim_cols, R::range_dim_cols, comb>::rC;
-  }; // class Choose
-
-public:
-  static const size_t r = Choose<LeftType, RightType>::r;
-  static const size_t rC = Choose<LeftType, RightType>::rC;
-
-  using LeftLocalFunctionType = typename LeftType::LocalFunctionType;
-  using RightLocalFunctionType = typename RightType::LocalFunctionType;
-  using DomainType = typename ElementFunctionInterface<E, r, rC, R>::DomainType;
-  using RangeType = typename RightType::LocalFunctionType::RangeType;
-  using ScalarRangeType = typename LeftType::LocalFunctionType::RangeType;
-  using DerivativeRangeType = typename ElementFunctionInterface<E, r, rC, R>::DerivativeRangeType;
-  using DerivativeRangeReturnType = typename ElementFunctionInterface<E, r, rC, R>::DerivativeRangeReturnType;
-
-private:
-  template <Combination cc, bool anything = true>
-  class Call
-  {
-    static_assert(!anything, "Nothing available for these combinations!");
-  }; // class Call
-
-  template <bool anything>
-  class Call<Combination::difference, anything>
-  {
-  public:
-    static std::string type()
-    {
-      return "difference";
-    }
-
-    static size_t order(const size_t left_order, const size_t right_order)
-    {
-      return std::max(left_order, right_order);
-    }
-
-    static RangeType evaluate(const LeftLocalFunctionType& left_local,
-                              const RightLocalFunctionType& right_local,
-                              const DomainType& point_in_reference_element,
-                              const Common::Parameter& param)
-    {
-      return left_local.evaluate(point_in_reference_element, param)
-             - right_local.evaluate(point_in_reference_element, param);
-    }
-
-    static DerivativeRangeReturnType jacobian(const LeftLocalFunctionType& left_local,
-                                              const RightLocalFunctionType& right_local,
-                                              const DomainType& point_in_reference_element,
-                                              const Common::Parameter& param)
-    {
-      return left_local.jacobian(point_in_reference_element, param)
-             - right_local.jacobian(point_in_reference_element, param);
-    } // ... jacobian(...)
-  }; // class Call< ..., difference >
-
-  template <bool anything>
-  class Call<Combination::sum, anything>
-  {
-  public:
-    static std::string type()
-    {
-      return "sum";
-    }
-
-    static size_t order(const size_t left_order, const size_t right_order)
-    {
-      return std::max(left_order, right_order);
-    }
-
-    static RangeType evaluate(const LeftLocalFunctionType& left_local,
-                              const RightLocalFunctionType& right_local,
-                              const DomainType& point_in_reference_element,
-                              const Common::Parameter& param)
-    {
-      return left_local.evaluate(point_in_reference_element, param)
-             + right_local.evaluate(point_in_reference_element, param);
-    } // ... evaluate(...)
-
-    static DerivativeRangeReturnType jacobian(const LeftLocalFunctionType& left_local,
-                                              const RightLocalFunctionType& right_local,
-                                              const DomainType& point_in_reference_element,
-                                              const Common::Parameter& param)
-    {
-      return left_local.jacobian(point_in_reference_element, param)
-             + right_local.jacobian(point_in_reference_element, param);
-    } // ... jacobian(...)
-  }; // class Call< ..., sum >
-
-  // left only scalar atm
-  template <bool anything>
-  class Call<Combination::product, anything>
-  {
-  public:
-    static std::string type()
-    {
-      return "product";
-    }
-
-    static size_t order(const size_t left_order, const size_t right_order)
-    {
-      return left_order + right_order;
-    }
-
-    static RangeType evaluate(const LeftLocalFunctionType& left_local,
-                              const RightLocalFunctionType& right_local,
-                              const DomainType& point_in_reference_element,
-                              const Common::Parameter& param)
-    {
-      ScalarRangeType left_eval = left_local.evaluate(point_in_reference_element, param);
-      RangeType right_eval = right_local.evaluate(point_in_reference_element, param);
-      if (left_eval.size() != 1)
-        DUNE_THROW(NotImplemented, "Only available for scalar left type!");
-      right_eval *= left_eval[0];
-      return right_eval;
-    } // ... evaluate(...)
-
-    static DerivativeRangeReturnType jacobian(const LeftLocalFunctionType& /*left_local*/,
-                                              const RightLocalFunctionType& /*right_local*/,
-                                              const DomainType& /*point_in_reference_element*/,
-                                              const Common::Parameter& /*param*/)
-    {
-      DUNE_THROW(NotImplemented, "If you need this, implement it!");
-      return DerivativeRangeReturnType();
-    }
-  }; // class Call< ..., product >
-
-public:
-  static std::string type()
-  {
-    return Call<comb>::type();
-  }
-
-  static size_t order(const size_t left_order, const size_t right_order)
-  {
-    return Call<comb>::order(left_order, right_order);
-  }
-
-  static RangeType evaluate(const LeftLocalFunctionType& left_local,
-                            const RightLocalFunctionType& right_local,
-                            const DomainType& point_in_reference_element,
-                            const Common::Parameter& param)
-  {
-    return Call<comb>::evaluate(left_local, right_local, point_in_reference_element, param);
-  }
-
-  static DerivativeRangeReturnType jacobian(const LeftLocalFunctionType& left_local,
-                                            const RightLocalFunctionType& right_local,
-                                            const DomainType& point_in_reference_element,
-                                            const Common::Parameter& param)
-  {
-    return Call<comb>::jacobian(left_local, right_local, point_in_reference_element, param);
-  }
-}; // class SelectCombined
-
-
-/**
- * \brief Generic combined local function.
- *
- * \note Most likely you do not want to use this class directly, but Combined.
- */
-template <class LeftType, class RightType, Combination type>
-class CombinedLocalFunction : public ElementFunctionInterface<typename SelectCombined<LeftType, RightType, type>::E,
-                                                              SelectCombined<LeftType, RightType, type>::r,
-                                                              SelectCombined<LeftType, RightType, type>::rC,
-                                                              typename SelectCombined<LeftType, RightType, type>::R>
-{
-  using BaseType = ElementFunctionInterface<typename SelectCombined<LeftType, RightType, type>::E,
-                                            SelectCombined<LeftType, RightType, type>::r,
-                                            SelectCombined<LeftType, RightType, type>::rC,
-                                            typename SelectCombined<LeftType, RightType, type>::R>;
-
-  using Select = SelectCombined<LeftType, RightType, type>;
-
-public:
-  using typename BaseType::ElementType;
-  using typename BaseType::DomainType;
-  using typename BaseType::RangeType;
-  using typename BaseType::DerivativeRangeType;
-  using typename BaseType::RangeReturnType;
-  using typename BaseType::DerivativeRangeReturnType;
-
-  CombinedLocalFunction(const LeftType& left, const RightType& right)
-    : BaseType()
-    , left_local_(left.local_function())
-    , right_local_(right.local_function())
-  {
-  }
-
-protected:
-  void post_bind(const ElementType& element) override final
-  {
-    left_local_->bind(element);
-    right_local_->bind(element);
-  }
-
-public:
-  int order(const XT::Common::Parameter& param = {}) const override final
-  {
-    return Select::order(left_local_->order(param), right_local_->order(param));
-  }
-
-  RangeReturnType evaluate(const DomainType& point_in_reference_element,
-                           const Common::Parameter& param = {}) const override final
-  {
-    return Select::evaluate(*left_local_, *right_local_, point_in_reference_element, param);
-  }
-
-  DerivativeRangeReturnType jacobian(const DomainType& point_in_reference_element,
-                                     const Common::Parameter& param = {}) const override final
-  {
-    return Select::jacobian(*left_local_, *right_local_, point_in_reference_element, param);
-  }
-
-private:
-  std::unique_ptr<typename LeftType::LocalFunctionType> left_local_;
-  std::unique_ptr<typename RightType::LocalFunctionType> right_local_;
-}; // class CombinedLocalFunction
-
-
-/**
- * \brief Generic combined function.
- *
- *        This class combines two given functions of type LeftType and RightType using the given combination
- *        Combination. This class (and any derived class, like Difference, Sum or Product) can be used in two ways:
- *        - You can pass references of the left and right operand to this class. This is done for instance when calling
- *          operator+, operator- or operator* on any function deriving from GridFunctionInterface:
-\code
-using IndicatorType = Functions::IndicatorFunction< ..., double>;
-IndicatorType one( ... );
-IndicatorType two( ... );
-// the following code
-auto difference = one - two;
-// is equivalent to
-Difference< IndicatorType, IndicatorType > difference(one, two);
-// and
-internal::Combined< IndicatorType, IndicatorType, Combination::difference > difference(one, tow);
-\endcode
- *          In this situation you are responsible to ensure that the arguments given are valid throughout the lifetime
- *          of this class. The following will lead to a segfault:
-\code
-using IndicatorType = Functions::IndicatorFunction< ..., double >;
-
-Difference< IndicatorType, IndicatorType > stupid_difference()
-{
-  IndicatorType one( ... );
-  IndicatorType two( ... );
-  return one - two;
-}
-\endcode
- *        - You can pass shared_ptr of the left and right operands to this class. In this case the following is valid:
-\code
-using IndicatorType = Functions::IndicatorFunction< ..., double >;
-
-Difference< IndicatorType, IndicatorType > stupid_difference()
-{
-  auto one = std::make_shared< IndicatorType >(1);
-  auto two = std::make_shared< IndicatorType >(2);
-  return Difference< IndicatorType, IndicatorType >(one, two)
-}
-\endcode
- *
- * \note  Most likely you do not want to use this class diretly, but one of Difference, Sum or Product.
- */
-template <class LeftType, class RightType, Combination comb>
-class Combined : public GridFunctionInterface<typename SelectCombined<LeftType, RightType, comb>::E,
-                                              SelectCombined<LeftType, RightType, comb>::r,
-                                              SelectCombined<LeftType, RightType, comb>::rC,
-                                              typename SelectCombined<LeftType, RightType, comb>::R>
-{
-  using BaseType = GridFunctionInterface<typename SelectCombined<LeftType, RightType, comb>::E,
-                                         SelectCombined<LeftType, RightType, comb>::r,
-                                         SelectCombined<LeftType, RightType, comb>::rC,
-                                         typename SelectCombined<LeftType, RightType, comb>::R>;
-
-  using LeftStorageType = Common::ConstStorageProvider<LeftType>;
-  using RightStorageType = Common::ConstStorageProvider<RightType>;
-  using ThisType = Combined<LeftType, RightType, comb>;
-
-public:
-  using ElementType = typename BaseType::ElementType;
-  using LocalFunctionType = typename BaseType::LocalFunctionType;
-
-  Combined(const LeftType& left, const RightType& right, const std::string nm = "")
-    : left_(Common::make_unique<LeftStorageType>(left))
-    , right_(Common::make_unique<RightStorageType>(right))
-    , name_(nm.empty()
-                ? SelectCombined<LeftType, RightType, comb>::type() + " of '" + left.name() + "' and '" + right.name()
-                      + "'"
-                : nm)
-  {
-  }
-
-  Combined(const std::shared_ptr<const LeftType> left,
-           const std::shared_ptr<const RightType> right,
-           const std::string nm = "")
-    : left_(Common::make_unique<LeftStorageType>(left))
-    , right_(Common::make_unique<RightStorageType>(right))
-    , name_(nm.empty()
-                ? SelectCombined<LeftType, RightType, comb>::type() + " of '" + left_->access().name() + "' and '"
-                      + right_->access().name()
-                      + "'"
-                : nm)
-  {
-  }
-
-  Combined(ThisType&& source) = default;
-
-  Combined(const ThisType& other) = delete;
-
-  ThisType& operator=(const ThisType& other) = delete;
-
-  ThisType& operator=(ThisType&& other) = delete;
-
-  std::unique_ptr<LocalFunctionType> local_function() const override final
-  {
-    using RealLocalFunctionType = CombinedLocalFunction<LeftType, RightType, comb>;
-    assert(left_);
-    assert(right_);
-    return Common::make_unique<RealLocalFunctionType>(left_->access(), right_->access());
-  } // ... local_function(...)
-
-  std::string type() const override final
-  {
-    return SelectCombined<LeftType, RightType, comb>::type() + " of '" + left_->access().type() + "' and '"
-           + right_->access().type() + "'";
-  } // ... type(...)
-
-  std::string name() const override final
-  {
-    return name_;
-  }
-
-private:
-  std::unique_ptr<const LeftStorageType> left_;
-  std::unique_ptr<const RightStorageType> right_;
-  const std::string name_;
-}; // class Combined
-
-
-} // namespace internal
-
-
-/**
- * \brief Function representing the difference between two functions.
- *
- * \see internal::Combined
- */
-template <class MinuendType, class SubtrahendType>
-class DifferenceFunction : public internal::Combined<MinuendType, SubtrahendType, internal::Combination::difference>
-{
-  using BaseType = internal::Combined<MinuendType, SubtrahendType, internal::Combination::difference>;
-
-public:
-  template <class... Args>
-  explicit DifferenceFunction(Args&&... args)
-    : BaseType(std::forward<Args>(args)...)
-  {
-  }
-}; // class DifferenceFunction
-
-
-/**
- * \brief Function representing the sum of two functions.
- *
- * \see internal::Combined
- */
-template <class LeftSummandType, class RightSummandType>
-class SumFunction : public internal::Combined<LeftSummandType, RightSummandType, internal::Combination::sum>
-{
-  using BaseType = internal::Combined<LeftSummandType, RightSummandType, internal::Combination::sum>;
-
-public:
-  template <class... Args>
-  explicit SumFunction(Args&&... args)
-    : BaseType(std::forward<Args>(args)...)
-  {
-  }
-}; // class SumFunction
-
-
-/**
- * \brief Function representing the product of two functions.
- *
- * \see internal::Combined
- */
-template <class LeftSummandType, class RightSummandType>
-class ProductFunction : public internal::Combined<LeftSummandType, RightSummandType, internal::Combination::product>
-{
-  using BaseType = internal::Combined<LeftSummandType, RightSummandType, internal::Combination::product>;
-
-public:
-  template <class... Args>
-  explicit ProductFunction(Args&&... args)
-    : BaseType(std::forward<Args>(args)...)
-  {
-  }
-}; // class ProductFunction
-
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<DifferenceFunction<T1, T2>> make_difference(const T1& left, const T2& right, Args&&... args)
-{
-  return std::make_shared<DifferenceFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<DifferenceFunction<T1, T2>>
-make_difference(std::shared_ptr<T1> left, std::shared_ptr<T2> right, Args&&... args)
-{
-  return std::make_shared<DifferenceFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<SumFunction<T1, T2>> make_sum(const T1& left, const T2& right, Args&&... args)
-{
-  return std::make_shared<SumFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<SumFunction<T1, T2>> make_sum(std::shared_ptr<T1> left, std::shared_ptr<T2> right, Args&&... args)
-{
-  return std::make_shared<SumFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<ProductFunction<T1, T2>> make_product(const T1& left, const T2& right, Args&&... args)
-{
-  return std::make_shared<ProductFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-template <class T1, class T2, class... Args>
-std::shared_ptr<ProductFunction<T1, T2>>
-make_product(std::shared_ptr<T1> left, std::shared_ptr<T2> right, Args&&... args)
-{
-  return std::make_shared<ProductFunction<T1, T2>>(left, right, std::forward<Args>(args)...);
-}
-
-
-} // namespace Functions
-} // namespace XT
-} // namespace Dune
-
-#endif // DUNE_XT_FUNCTIONS_BASE_COMBINED_HH
-- 
GitLab