From 5b5427260faeb1b9212fc0c927d722d7f643d1c3 Mon Sep 17 00:00:00 2001
From: Felix Schindler <felix.schindler@wwu.de>
Date: Thu, 8 Aug 2019 11:02:26 +0200
Subject: [PATCH] [integrands] add LocalIntersectionProductIntegrand

---
 dune/gdt/local/integrands/product.hh | 176 +++++++++++++++++++++++++--
 1 file changed, 164 insertions(+), 12 deletions(-)

diff --git a/dune/gdt/local/integrands/product.hh b/dune/gdt/local/integrands/product.hh
index 8cb7c1097..418d00b96 100644
--- a/dune/gdt/local/integrands/product.hh
+++ b/dune/gdt/local/integrands/product.hh
@@ -57,8 +57,6 @@ public:
               new XT::Functions::ConstantFunction<d, 1, 1, F>(inducing_value),
               new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r)))))
     , local_function_(inducing_function_.access().local_function())
-    , test_basis_values_()
-    , ansatz_basis_values_()
   {}
 
   LocalElementProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
@@ -69,8 +67,6 @@ public:
               inducing_function,
               new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r)))))
     , local_function_(inducing_function_.access().local_function())
-    , test_basis_values_()
-    , ansatz_basis_values_()
   {}
 
   LocalElementProductIntegrand(const XT::Functions::GridFunctionInterface<E, 1, 1, F>& inducing_function)
@@ -82,8 +78,6 @@ public:
               new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>(
                   new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r))))))
     , local_function_(inducing_function_.access().local_function())
-    , test_basis_values_()
-    , ansatz_basis_values_()
   {}
 
   template <class E_, typename = std::enable_if_t<std::is_same<E_, E>::value && r != 1, void>>
@@ -91,16 +85,12 @@ public:
     : BaseType()
     , inducing_function_(inducing_function)
     , local_function_(inducing_function_.access().local_function())
-    , test_basis_values_()
-    , ansatz_basis_values_()
   {}
 
   LocalElementProductIntegrand(const ThisType& other)
     : BaseType(other.parameter_type())
     , inducing_function_(other.inducing_function_)
     , local_function_(inducing_function_.access().local_function())
-    , test_basis_values_()
-    , ansatz_basis_values_()
   {}
 
   LocalElementProductIntegrand(ThisType&& source) = default;
@@ -155,8 +145,170 @@ private:
 }; // class LocalElementProductIntegrand
 
 
-/// \todo add LocalIntersectionProductIntegrand
-///
+/**
+ * Given an inducing function f, computes `<f> * phi * psi` for all combinations of phi and psi in the bases, where
+ * `<f>` denotes the average of f evaluated on the inside and evaluated on the outside.
+ *
+ * \note Note that f can also be given as a scalar value or omitted.
+ */
+template <class I, size_t r = 1, class TR = double, class F = double, class AR = TR>
+class LocalIntersectionProductIntegrand : public LocalQuaternaryIntersectionIntegrandInterface<I, r, 1, TR, F, r, 1, AR>
+{
+  using ThisType = LocalIntersectionProductIntegrand<I, r, TR, F, AR>;
+  using BaseType = LocalQuaternaryIntersectionIntegrandInterface<I, r, 1, TR, F, r, 1, AR>;
+
+public:
+  using BaseType::d;
+  using typename BaseType::DomainType;
+  using typename BaseType::E;
+  using typename BaseType::IntersectionType;
+  using typename BaseType::LocalAnsatzBasisType;
+  using typename BaseType::LocalTestBasisType;
+
+  using GridFunctionType = XT::Functions::GridFunctionInterface<E, r, r, F>;
+
+  LocalIntersectionProductIntegrand(const F& inducing_value = F(1))
+    : BaseType()
+    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>(
+          new XT::Functions::ProductFunction<XT::Functions::ConstantFunction<d, 1, 1, F>,
+                                             XT::Functions::ConstantFunction<d, r, r, F>>(
+              new XT::Functions::ConstantFunction<d, 1, 1, F>(inducing_value),
+              new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r)))))
+    , local_function_in_(inducing_function_.access().local_function())
+    , local_function_out_(inducing_function_.access().local_function())
+  {}
+
+  LocalIntersectionProductIntegrand(const XT::Functions::FunctionInterface<d, 1, 1, F>& inducing_function)
+    : BaseType()
+    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>(
+          new XT::Functions::ProductFunction<XT::Functions::FunctionInterface<d, 1, 1, F>,
+                                             XT::Functions::ConstantFunction<d, r, r, F>>(
+              inducing_function,
+              new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r)))))
+    , local_function_in_(inducing_function_.access().local_function())
+    , local_function_out_(inducing_function_.access().local_function())
+  {}
+
+  LocalIntersectionProductIntegrand(const XT::Functions::GridFunctionInterface<E, 1, 1, F>& inducing_function)
+    : BaseType()
+    , inducing_function_(new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>(
+          new XT::Functions::ProductGridFunction<XT::Functions::GridFunctionInterface<E, 1, 1, F>,
+                                                 XT::Functions::GridFunctionInterface<E, r, r, F>>(
+              inducing_function,
+              new XT::Functions::FunctionAsGridFunctionWrapper<E, r, r, F>(
+                  new XT::Functions::ConstantFunction<d, r, r, F>(XT::LA::eye_matrix<FieldMatrix<F, r, r>>(r))))))
+    , local_function_in_(inducing_function_.access().local_function())
+    , local_function_out_(inducing_function_.access().local_function())
+  {}
+
+  template <class E_, typename = std::enable_if_t<std::is_same<E_, E>::value && r != 1, void>>
+  LocalIntersectionProductIntegrand(const XT::Functions::GridFunctionInterface<E_, r, r, F>& inducing_function)
+    : BaseType()
+    , inducing_function_(inducing_function)
+    , local_function_in_(inducing_function_.access().local_function())
+    , local_function_out_(inducing_function_.access().local_function())
+  {}
+
+  LocalIntersectionProductIntegrand(const ThisType& other)
+    : BaseType(other.parameter_type())
+    , inducing_function_(other.inducing_function_)
+    , local_function_in_(inducing_function_.access().local_function())
+    , local_function_out_(inducing_function_.access().local_function())
+  {}
+
+  LocalIntersectionProductIntegrand(ThisType&& source) = default;
+
+  std::unique_ptr<BaseType> copy() const override final
+  {
+    return std::make_unique<ThisType>(*this);
+  }
+
+protected:
+  void post_bind(const IntersectionType& intersct) override final
+  {
+    auto inside_element = intersct.inside();
+    local_function_in_->bind(inside_element);
+    if (intersct.neighbor()) {
+      local_function_out_->bind(intersct.outside());
+    } else
+      local_function_out_->bind(intersct.inside());
+  } // ... post_bind(...)
+
+public:
+  int order(const LocalTestBasisType& test_basis_inside,
+            const LocalAnsatzBasisType& ansatz_basis_inside,
+            const LocalTestBasisType& test_basis_outside,
+            const LocalAnsatzBasisType& ansatz_basis_outside,
+            const XT::Common::Parameter& param = {}) const override final
+  {
+    return std::max(local_function_in_->order(param), local_function_out_->order(param))
+           + std::max(test_basis_inside.order(param), test_basis_outside.order(param))
+           + std::max(ansatz_basis_outside.order(param), ansatz_basis_outside.order(param));
+  }
+
+  using BaseType::evaluate;
+
+  void evaluate(const LocalTestBasisType& test_basis_inside,
+                const LocalAnsatzBasisType& ansatz_basis_inside,
+                const LocalTestBasisType& test_basis_outside,
+                const LocalAnsatzBasisType& ansatz_basis_outside,
+                const DomainType& point_in_reference_intersection,
+                DynamicMatrix<F>& result_in_in,
+                DynamicMatrix<F>& result_in_out,
+                DynamicMatrix<F>& result_out_in,
+                DynamicMatrix<F>& result_out_out,
+                const XT::Common::Parameter& param = {}) const override final
+  {
+    // prepare sotrage
+    const size_t rows_in = test_basis_inside.size(param);
+    const size_t rows_out = test_basis_outside.size(param);
+    const size_t cols_in = ansatz_basis_inside.size(param);
+    const size_t cols_out = ansatz_basis_outside.size(param);
+    const auto ensure_size = [](auto& m, const auto& rws, const auto& cls) {
+      if (m.rows() < rws || m.cols() < cls)
+        m.resize(rws, cls);
+    };
+    ensure_size(result_in_in, rows_in, cols_in);
+    ensure_size(result_in_out, rows_in, cols_out);
+    ensure_size(result_out_in, rows_out, cols_in);
+    ensure_size(result_out_out, rows_out, cols_out);
+    // evaluate
+    const auto point_in_inside_reference_element =
+        this->intersection().geometryInInside().global(point_in_reference_intersection);
+    test_basis_inside.evaluate(point_in_inside_reference_element, test_basis_in_values_, param);
+    ansatz_basis_inside.evaluate(point_in_inside_reference_element, ansatz_basis_in_values_, param);
+    const auto function_value_in = local_function_in_->evaluate(point_in_inside_reference_element, param);
+    const auto point_in_outside_reference_element =
+        this->intersection().geometryInOutside().global(point_in_reference_intersection);
+    test_basis_outside.evaluate(point_in_outside_reference_element, test_basis_out_values_, param);
+    ansatz_basis_outside.evaluate(point_in_outside_reference_element, ansatz_basis_out_values_, param);
+    const auto function_value_out = local_function_out_->evaluate(point_in_outside_reference_element, param);
+    // compute integrand
+    const auto average_function_value = (function_value_in + function_value_out) * 0.5;
+    for (size_t ii = 0; ii < rows_in; ++ii) {
+      for (size_t jj = 0; jj < cols_in; ++jj)
+        result_in_in[ii][jj] = (average_function_value * ansatz_basis_in_values_[jj]) * test_basis_in_values_[ii];
+      for (size_t jj = 0; jj < cols_out; ++jj)
+        result_in_out[ii][jj] = (average_function_value * ansatz_basis_out_values_[jj]) * test_basis_in_values_[ii];
+    }
+    for (size_t ii = 0; ii < rows_out; ++ii) {
+      for (size_t jj = 0; jj < cols_in; ++jj)
+        result_out_in[ii][jj] = (average_function_value * ansatz_basis_in_values_[jj]) * test_basis_out_values_[ii];
+      for (size_t jj = 0; jj < cols_out; ++jj)
+        result_out_out[ii][jj] = (average_function_value * ansatz_basis_out_values_[jj]) * test_basis_out_values_[ii];
+    }
+  } // ... evaluate(...)
+
+private:
+  const XT::Common::ConstStorageProvider<GridFunctionType> inducing_function_;
+  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_in_;
+  std::unique_ptr<typename GridFunctionType::LocalFunctionType> local_function_out_;
+  mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_in_values_;
+  mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_out_values_;
+  mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_in_values_;
+  mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_out_values_;
+}; // class LocalIntersectionProductIntegrand
+
 
 } // namespace GDT
 } // namespace Dune
-- 
GitLab