From cb6d2136f1ad53b258665c1dc22bafb6c18675dc Mon Sep 17 00:00:00 2001
From: Felix Schindler <felix.schindler@wwu.de>
Date: Thu, 7 Mar 2019 16:05:30 +0100
Subject: [PATCH] [spaces.rt] implement interpolation of the global FE

---
 dune/gdt/spaces/basis/raviart-thomas.hh | 136 +++++++++++++++++++++++-
 1 file changed, 131 insertions(+), 5 deletions(-)

diff --git a/dune/gdt/spaces/basis/raviart-thomas.hh b/dune/gdt/spaces/basis/raviart-thomas.hh
index 3b831f13a..8fd4c3269 100644
--- a/dune/gdt/spaces/basis/raviart-thomas.hh
+++ b/dune/gdt/spaces/basis/raviart-thomas.hh
@@ -31,6 +31,8 @@ namespace GDT {
  * - flipping of shape functions to ensure continuity of normal component
  * - Piola transformation
  * - left-multiplication by the geometry transformations jacobian inverse transpose in jacobian
+ *
+ * \todo Somehow make use of the LocalRaviartThomasInterpolation and get rid of the duplicate code.
  */
 template <class GL, class R = double>
 class RaviartThomasGlobalBasis : public GlobalBasisInterface<GL, GL::dimension, 1, R>
@@ -227,12 +229,136 @@ private:
 
     using BaseType::interpolate;
 
-    void interpolate(const std::function<RangeType(DomainType)>& /*element_function*/,
-                     const int /*order*/,
-                     DynamicVector<R>& /*dofs*/) const override final
+    void interpolate(const std::function<RangeType(DomainType)>& element_function,
+                     const int element_function_order,
+                     DynamicVector<R>& dofs) const override final
     {
-      DUNE_THROW(NotImplemented, "");
-    }
+      // prepare
+      const size_t sz = this->size();
+      if (dofs.size() != sz)
+        dofs.resize(sz);
+      std::vector<bool> local_key_was_handled(sz, false);
+      // determine the face dofs, therefore walk the intersections
+      for (auto&& intersection : intersections(self_.grid_view_, this->element())) {
+        const auto intersection_to_local_key_map = finite_element().coefficients().local_key_indices(1);
+        const auto intersection_index = intersection.indexInInside();
+        const auto& local_keys_assosiated_with_intersection = intersection_to_local_key_map[intersection_index];
+        if (local_keys_assosiated_with_intersection.size() > 0) {
+          const auto intersection_fe = make_local_orthonormal_finite_element<D, d - 1, R>(
+              intersection.geometry().type(), finite_element().order());
+          const auto& intersection_Pk_basis = intersection_fe->basis();
+          DUNE_THROW_IF(intersection_Pk_basis.size() != local_keys_assosiated_with_intersection.size(),
+                        Exceptions::interpolation_error,
+                        "intersection_Pk_basis.size() = " << intersection_Pk_basis.size()
+                                                          << "\n   local_keys_assosiated_with_intersection.size() = "
+                                                          << local_keys_assosiated_with_intersection.size());
+          XT::LA::CommonDenseMatrix<R> lhs(
+              local_keys_assosiated_with_intersection.size(), intersection_Pk_basis.size(), 0);
+          XT::LA::CommonDenseVector<R> rhs(intersection_Pk_basis.size(), 0);
+          // do a face quadrature
+          for (auto&& quadrature_point :
+               QuadratureRules<D, d - 1>::rule(intersection.geometry().type(),
+                                               std::max(this->order() + intersection_Pk_basis.order(),
+                                                        element_function_order + intersection_Pk_basis.order()))) {
+            const auto point_on_reference_intersection = quadrature_point.position();
+            const auto point_in_reference_element =
+                intersection.geometryInInside().global(point_on_reference_intersection);
+            const auto quadrature_weight = quadrature_point.weight();
+            const auto normal = intersection.unitOuterNormal(point_on_reference_intersection);
+            const auto integration_factor = intersection.geometry().integrationElement(point_on_reference_intersection);
+            const auto rt_basis_values = this->evaluate_set(point_in_reference_element);
+            const auto intersection_Pk_basis_values = intersection_Pk_basis.evaluate(point_on_reference_intersection);
+            const auto element_function_values = element_function(point_in_reference_element);
+            for (size_t ii = 0; ii < local_keys_assosiated_with_intersection.size(); ++ii) {
+              const size_t local_key_index = local_keys_assosiated_with_intersection[ii];
+              for (size_t jj = 0; jj < intersection_Pk_basis.size(); ++jj)
+                lhs.add_to_entry(ii,
+                                 jj,
+                                 quadrature_weight * integration_factor * (rt_basis_values[local_key_index] * normal)
+                                     * intersection_Pk_basis_values[jj]);
+            }
+            for (size_t jj = 0; jj < intersection_Pk_basis.size(); ++jj)
+              rhs[jj] += quadrature_weight * integration_factor * (element_function_values * normal)
+                         * intersection_Pk_basis_values[jj];
+          }
+          XT::LA::CommonDenseVector<R> intersection_dofs(local_keys_assosiated_with_intersection.size(), 0);
+          try {
+            intersection_dofs = XT::LA::solve(lhs, rhs);
+          } catch (const XT::LA::Exceptions::linear_solver_failed& ee) {
+            DUNE_THROW(Exceptions::interpolation_error,
+                       "Failed to solve for DoFs associated with intersection "
+                           << intersection_index << ", this was the original error:\n   " << ee.what());
+          }
+          for (size_t ii = 0; ii < local_keys_assosiated_with_intersection.size(); ++ii) {
+            const size_t local_key_index = local_keys_assosiated_with_intersection[ii];
+            assert(!local_key_was_handled[local_key_index]);
+            dofs[local_key_index] = intersection_dofs[ii];
+            local_key_was_handled[local_key_index] = true;
+          }
+        }
+      }
+      // determine the volume dofs
+      const auto element_to_local_key_map = finite_element().coefficients().local_key_indices(0);
+      const auto& local_keys_assosiated_with_element = element_to_local_key_map[0];
+      if (local_keys_assosiated_with_element.size() > 0) {
+        DUNE_THROW_IF(this->order() < 1,
+                      Exceptions::interpolation_error,
+                      "DoFs associated with the element only make sense for orders >= 1!");
+        const auto element_fe = make_local_orthonormal_finite_element<D, d, R, d>(this->element().geometry().type(),
+                                                                                  finite_element().order() - 1);
+        const auto& element_Pkminus1_basis = element_fe->basis();
+        DUNE_THROW_IF(element_Pkminus1_basis.size() != local_keys_assosiated_with_element.size(),
+                      Exceptions::interpolation_error,
+                      "element_Pkminus1_basis.size() = " << element_Pkminus1_basis.size()
+                                                         << "\n   local_keys_assosiated_with_element.size() = "
+                                                         << local_keys_assosiated_with_element.size());
+        XT::LA::CommonDenseMatrix<R> lhs(local_keys_assosiated_with_element.size(), element_Pkminus1_basis.size(), 0);
+        XT::LA::CommonDenseVector<R> rhs(element_Pkminus1_basis.size(), 0);
+        // do a volume quadrature
+        for (auto&& quadrature_point :
+             QuadratureRules<D, d>::rule(this->element().geometry().type(),
+                                         std::max(this->order() + element_Pkminus1_basis.order(),
+                                                  element_function_order + element_Pkminus1_basis.order()))) {
+          const auto point_in_reference_element = quadrature_point.position();
+          const auto quadrature_weight = quadrature_point.weight();
+          const auto integration_factor = this->element().geometry().integrationElement(point_in_reference_element);
+          const auto rt_basis_values = this->evaluate_set(point_in_reference_element);
+          const auto element_Pkminus1_basis_values = element_Pkminus1_basis.evaluate(point_in_reference_element);
+          const auto element_function_values = element_function(point_in_reference_element);
+          for (size_t ii = 0; ii < local_keys_assosiated_with_element.size(); ++ii) {
+            const size_t local_key_index = local_keys_assosiated_with_element[ii];
+            for (size_t jj = 0; jj < element_Pkminus1_basis.size(); ++jj)
+              lhs.add_to_entry(ii,
+                               jj,
+                               quadrature_weight * integration_factor
+                                   * (rt_basis_values[local_key_index] * element_Pkminus1_basis_values[jj]));
+          }
+          for (size_t jj = 0; jj < element_Pkminus1_basis.size(); ++jj)
+            rhs[jj] +=
+                quadrature_weight * integration_factor * (element_function_values * element_Pkminus1_basis_values[jj]);
+        }
+        XT::LA::CommonDenseVector<R> element_dofs(local_keys_assosiated_with_element.size(), 0);
+        try {
+          element_dofs = XT::LA::solve(lhs, rhs);
+        } catch (const XT::LA::Exceptions::linear_solver_failed& ee) {
+          DUNE_THROW(Exceptions::interpolation_error,
+                     "Failed to solve for volume DoFs, this was the original error:\n   " << ee.what());
+        }
+        for (size_t ii = 0; ii < local_keys_assosiated_with_element.size(); ++ii) {
+          const size_t local_key_index = local_keys_assosiated_with_element[ii];
+          assert(!local_key_was_handled[local_key_index]);
+          dofs[local_key_index] = element_dofs[ii];
+          local_key_was_handled[local_key_index] = true;
+        }
+      }
+      // final checks that there are no other dofs left
+      for (size_t ii = 0; ii < sz; ++ii)
+        DUNE_THROW_IF(!local_key_was_handled[ii],
+                      Exceptions::interpolation_error,
+                      "The following DoF is neither associated with an intersection, nor with the element!"
+                          << "\n   local DoF index: " << ii
+                          << "\n   associated local_key: " << finite_element().coefficients().local_key(ii));
+    } // ... interpolate(...)
 
   private:
     const RaviartThomasGlobalBasis<GL, R>& self_;
-- 
GitLab