From 6f902b1cf0330f2a1984ec3ec1bf51920dbc9423 Mon Sep 17 00:00:00 2001
From: Felix Schindler <felix.schindler@wwu.de>
Date: Tue, 23 Feb 2021 09:44:23 +0100
Subject: [PATCH] [local.integrands] add
 LocalIntersectionNormalComponentProductIntegrand

---
 dune/gdt/local/integrands/product.hh | 113 +++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/dune/gdt/local/integrands/product.hh b/dune/gdt/local/integrands/product.hh
index ab8a9fc58..fe209f629 100644
--- a/dune/gdt/local/integrands/product.hh
+++ b/dune/gdt/local/integrands/product.hh
@@ -386,6 +386,119 @@ private:
 }; // class LocalIntersectionProductIntegrand
 
 
+/**
+ * Given an inducing vector-valued function f, computes `(f * n) * phi * psi` for all combinations of phi and psi in the bases.
+ *
+ * \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 LocalIntersectionNormalComponentProductIntegrand : public LocalBinaryIntersectionIntegrandInterface<I, r, 1, TR, F, r, 1, AR>
+{
+  using ThisType = LocalIntersectionNormalComponentProductIntegrand;
+  using BaseType = LocalBinaryIntersectionIntegrandInterface<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, d, 1, F>;
+
+  LocalIntersectionNormalComponentProductIntegrand(XT::Functions::GridFunction<E, d, 1, F> weight,
+                                                   const bool use_inside_bases = true,
+                                                   const std::string& logging_prefix = "")
+    : BaseType({},
+               logging_prefix.empty() ? "LocalIntersectionNormalComponentProductIntegrand" : logging_prefix,
+               /*logging_disabled=*/logging_prefix.empty())
+    , weight_(weight.copy_as_grid_function())
+    , local_weight_(weight_->local_function())
+    , inside_(use_inside_bases)
+  {}
+
+  LocalIntersectionNormalComponentProductIntegrand(const ThisType& other)
+    : BaseType(other)
+    , weight_(other.weight_->copy_as_grid_function())
+    , local_weight_(weight_->local_function())
+    , inside_(other.inside_)
+  {}
+
+  LocalIntersectionNormalComponentProductIntegrand(ThisType&& source) = default;
+
+  std::unique_ptr<BaseType> copy_as_binary_intersection_integrand() const override final
+  {
+    return std::make_unique<ThisType>(*this);
+  }
+
+protected:
+  void post_bind(const IntersectionType& intersct) override final
+  {
+    if (inside_)
+      local_weight_->bind(intersct.inside());
+    else {
+      DUNE_THROW_IF(!intersct.neighbor(), Exceptions::integrand_error, "");
+      local_weight_->bind(intersct.outside());
+    }
+  } // ... post_bind(...)
+
+public:
+  bool inside() const override final
+  {
+    return inside_;
+  }
+
+  int order(const LocalTestBasisType& test_basis,
+            const LocalAnsatzBasisType& ansatz_basis,
+            const XT::Common::Parameter& param = {}) const override final
+  {
+    return local_weight_->order(param) + test_basis.order(param) + ansatz_basis.order(param);
+  }
+
+  using BaseType::evaluate;
+
+  void evaluate(const LocalTestBasisType& test_basis,
+                const LocalAnsatzBasisType& ansatz_basis,
+                const DomainType& point_in_reference_intersection,
+                DynamicMatrix<F>& result,
+                const XT::Common::Parameter& param = {}) const override final
+  {
+    // prepare sotrage
+    this->ensure_size_and_clear_results(test_basis, ansatz_basis, result, param);
+    // evaluate
+    F weight;
+    const auto normal = this->intersection().unitOuterNormal(point_in_reference_intersection);
+    if (inside_) {
+      const auto point_in_inside_reference_element =
+          this->intersection().geometryInInside().global(point_in_reference_intersection);
+      test_basis.evaluate(point_in_inside_reference_element, test_basis_values_, param);
+      ansatz_basis.evaluate(point_in_inside_reference_element, ansatz_basis_values_, param);
+      weight = (local_weight_->evaluate(point_in_inside_reference_element, param) * normal);
+    } else {
+      const auto point_in_outside_reference_element =
+          this->intersection().geometryInOutside().global(point_in_reference_intersection);
+      test_basis.evaluate(point_in_outside_reference_element, test_basis_values_, param);
+      ansatz_basis.evaluate(point_in_outside_reference_element, ansatz_basis_values_, param);
+      weight = (local_weight_->evaluate(point_in_outside_reference_element, param) * normal);
+    }
+    // compute integrand
+    const size_t rows = test_basis.size(param);
+    const size_t cols = ansatz_basis.size(param);
+    for (size_t ii = 0; ii < rows; ++ii)
+      for (size_t jj = 0; jj < cols; ++jj)
+        result[ii][jj] = (weight * ansatz_basis_values_[jj]) * test_basis_values_[ii];
+  } // ... evaluate(...)
+
+private:
+  const std::unique_ptr<XT::Functions::GridFunctionInterface<E, d, 1, F>> weight_;
+  std::unique_ptr<typename XT::Functions::GridFunctionInterface<E, d, 1, F>::LocalFunctionType> local_weight_;
+  const bool inside_;
+  mutable std::vector<typename LocalTestBasisType::RangeType> test_basis_values_;
+  mutable std::vector<typename LocalAnsatzBasisType::RangeType> ansatz_basis_values_;
+}; // class LocalIntersectionNormalComponentProductIntegrand
+
+
 template <class E_or_I, size_t r = 1, class TR = double, class F = double, class AR = TR>
 class LocalProductIntegrand
   : public std::conditional_t<XT::Grid::is_entity<E_or_I>::value,
-- 
GitLab