From 449811fe4e94002a8eba719e014cebef5e61d35b Mon Sep 17 00:00:00 2001
From: "Praetorius, Simon" <simon.praetorius@tu-dresden.de>
Date: Wed, 28 Aug 2019 12:32:46 +0200
Subject: [PATCH] added twist utilities to flip the order of edge DOFs

---
 src/amdis/functions/GlobalIdSet.hpp           | 67 +++++++++++------
 .../linearalgebra/istl/Communication.hpp      |  1 -
 src/amdis/linearalgebra/mtl/ITL_Solver.hpp    |  2 +-
 src/amdis/linearalgebra/mtl/UmfpackRunner.hpp |  1 -
 src/amdis/utility/CMakeLists.txt              |  1 +
 src/amdis/utility/Twist.hpp                   | 73 +++++++++++++++++++
 test/ISTLCommTest.cpp                         |  3 +
 7 files changed, 123 insertions(+), 25 deletions(-)
 create mode 100644 src/amdis/utility/Twist.hpp

diff --git a/src/amdis/functions/GlobalIdSet.hpp b/src/amdis/functions/GlobalIdSet.hpp
index ee0674c2..29f56a69 100644
--- a/src/amdis/functions/GlobalIdSet.hpp
+++ b/src/amdis/functions/GlobalIdSet.hpp
@@ -11,11 +11,12 @@
 #include <dune/grid/common/gridenums.hh>
 #include <dune/localfunctions/common/localkey.hh>
 
+#include <amdis/Output.hpp>
 #include <amdis/common/Apply.hpp>
 #include <amdis/common/ForEach.hpp>
 #include <amdis/common/TupleUtility.hpp>
 #include <amdis/functions/Nodes.hpp>
-#include <amdis/Output.hpp>
+#include <amdis/utility/Twist.hpp>
 
 namespace Dune
 {
@@ -88,9 +89,20 @@ namespace AMDiS
     {
       using Super = std::pair<EntityIdType, std::size_t>;
 
-      IdType(int i = 0) : Super() {};
+      IdType(std::size_t i = 0) : Super(EntityIdType{}, i) {};
       using Super::Super;
 
+      IdType& operator++()
+      {
+        ++this->second;
+        return *this;
+      }
+
+      IdType operator+(std::size_t shift) const
+      {
+        return IdType{this->first, this->second + shift};
+      }
+
       friend std::ostream& operator<<(std::ostream& os, IdType const& id)
       {
         os << "(" << id.first << "," << id.second << ")";
@@ -101,11 +113,13 @@ namespace AMDiS
     using PreBasis = typename GlobalBasis::PreBasis;
     using TreePath = typename GlobalBasis::PrefixPath;
     using NodeIdSet = AMDiS::NodeIdSet<PreBasis, TreePath>;
+    using Twist = AMDiS::Twist<typename Grid::GlobalIdSet, GridView::dimension>;
 
   public:
     GlobalBasisIdSet(GlobalBasis const& globalBasis)
       : tree_(makeNode(globalBasis.preBasis(), TreePath{}))
       , nodeIdSet_(globalBasis.gridView())
+      , twist_(globalBasis.gridView().grid().globalIdSet())
     {
       Dune::Functions::initializeTree(tree_);
     }
@@ -120,8 +134,9 @@ namespace AMDiS
     {
       Dune::Functions::bindTree(tree_, element);
       nodeIdSet_.bind(tree_);
+      twist_.bind(element);
       data_.resize(size());
-      nodeIdSet_.fillIn(data_.begin());
+      nodeIdSet_.fillIn(twist_, data_.begin());
     }
 
     /// \brief unbind from the element
@@ -162,6 +177,7 @@ namespace AMDiS
   protected:
     Tree tree_;
     NodeIdSet nodeIdSet_;
+    Twist twist_;
     using Data = std::pair<IdType, PartitionType>;
     std::vector<Data> data_;
   };
@@ -195,6 +211,7 @@ namespace AMDiS
   public:
     NodeIdSet(GridView const& gridView)
       : gridView_(gridView)
+      , sizes_{}
     {}
 
     /// \brief Bind the idset to a tree node
@@ -202,6 +219,15 @@ namespace AMDiS
     {
       node_ = &node;
       size_ = node_->finiteElement().size();
+
+      std::fill(std::begin(sizes_), std::end(sizes_), 0u);
+      for (size_type i = 0; i < size_ ; ++i) {
+        Dune::LocalKey const& localKey = node_->finiteElement().localCoefficients().localKey(i);
+        sizes_[localKey.codim()]++;
+      }
+      auto refElem = Dune::referenceElement<double,GridView::dimension>(node_->element().type());
+      for (size_type c = 0; c <= GridView::dimension ; ++c)
+        sizes_[c] /= refElem.size(c);
     }
 
     /// \brief Unbind the idset
@@ -218,8 +244,8 @@ namespace AMDiS
 
     /// \brief Maps from subtree index set [0..size-1] to a globally unique id in global basis
     // [[expects: node_ != nullptr]]
-    template <class It>
-    It fillIn(It it, size_type shift = 0) const
+    template <class Twist, class It>
+    It fillIn(Twist const& twist, It it, size_type shift = 0) const
     {
       const auto& gridIdSet = gridView_.grid().globalIdSet();
 
@@ -227,11 +253,7 @@ namespace AMDiS
         Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i);
         unsigned int s = localKey.subEntity();
         unsigned int c = localKey.codim();
-        unsigned int idx = localKey.index();
-        if (!(c == GridView::dimension || c == 0 || idx == 0))
-          DUNE_THROW(Dune::NotImplemented, "Bases with more then one DoF per subentity are not supported.");
-
-        it->first = {gridIdSet.subId(node_->element(), s, c), shift + idx};
+        it->first = {gridIdSet.subId(node_->element(), s, c), shift + twist.get(localKey,sizes_[c])};
 
         it->second = Dune::Hybrid::switchCases(std::make_index_sequence<dim+1>{}, c,
           [&](auto codim) { return node_->element().template subEntity<codim>(s).partitionType(); },
@@ -248,6 +270,7 @@ namespace AMDiS
     GridView gridView_;
     const Node* node_ = nullptr;
     size_type size_ = 0;
+    std::array<unsigned int,GridView::dimension+1> sizes_;
   };
 
 
@@ -293,13 +316,13 @@ namespace AMDiS
 
     /// \brief Maps from subtree index set [0..size-1] to a globally unique id in global basis
     // [[expects: node_ != nullptr]]
-    template <class It>
-    It fillIn(It it, size_type shift = 0) const
+    template <class Twist, class It>
+    It fillIn(Twist const& twist, It it, size_type shift = 0) const
     {
       for (std::size_t child = 0; child < children; ++child)
       {
         size_type subTreeSize = subIds_.size();
-        it = subIds_.fillIn(it, shift);
+        it = subIds_.fillIn(twist, it, shift);
         shift += subTreeSize;
       }
       return it;
@@ -370,13 +393,13 @@ namespace AMDiS
 
     /// \brief Maps from subtree index set [0..size-1] to a globally unique id in global basis
     // [[expects: node_ != nullptr]]
-    template <class It>
-    It fillIn(It it, size_type shift = 0) const
+    template <class Twist, class It>
+    It fillIn(Twist const& twist, It it, size_type shift = 0) const
     {
       Tools::for_each(idsTuple_, [&](auto const& ids)
       {
         size_type subTreeSize = ids.size();
-        it = ids.fillIn(it, shift);
+        it = ids.fillIn(twist, it, shift);
         shift += subTreeSize;
       });
       return it;
@@ -443,15 +466,15 @@ namespace AMDiS
 
     /// \brief Maps from subtree index set [0..size-1] to a globally unique id in global basis
     // [[expects: node_ != nullptr]]
-    template <class It>
-    It fillIn(It it, size_type shift = 0) const
+    template <class Twist, class It>
+    It fillIn(Twist const& twist, It it, size_type shift = 0) const
     {
       for (int child = 0; child < dow; ++child) {
         size_type subTreeSize = pq2NodeIdSet_.size();
-        it = pq2NodeIdSet_.fillIn(it, shift);
+        it = pq2NodeIdSet_.fillIn(twist, it, shift);
         shift += subTreeSize;
       }
-      it = pq1NodeIdSet_.fillIn(it, shift);
+      it = pq1NodeIdSet_.fillIn(twist, it, shift);
       return it;
     }
 
@@ -496,8 +519,8 @@ namespace AMDiS
 
     /// \brief Maps from subtree index set [0..size-1] to a globally unique id in global basis
     // [[expects: node_ != nullptr]]
-    template <class It>
-    It fillIn(It it, size_type shift = 0) const
+    template <class Twist, class It>
+    It fillIn(Twist const& /*twist*/, It it, size_type shift = 0) const
     {
       const auto& gridIdSet = gridView_.grid().globalIdSet();
       auto elementId = gridIdSet.id(node_->element());
diff --git a/src/amdis/linearalgebra/istl/Communication.hpp b/src/amdis/linearalgebra/istl/Communication.hpp
index eb63684f..fc56b2b6 100644
--- a/src/amdis/linearalgebra/istl/Communication.hpp
+++ b/src/amdis/linearalgebra/istl/Communication.hpp
@@ -79,7 +79,6 @@ namespace AMDiS
   /// Dummy implementation for ISTL-specific communication when no MPI is found
   template <class Basis>
   class ISTLCommunication
-      : public DefaultCommunication<Basis>
   {
     using Self = ISTLCommunication;
 
diff --git a/src/amdis/linearalgebra/mtl/ITL_Solver.hpp b/src/amdis/linearalgebra/mtl/ITL_Solver.hpp
index fd800d0c..bc2360a6 100644
--- a/src/amdis/linearalgebra/mtl/ITL_Solver.hpp
+++ b/src/amdis/linearalgebra/mtl/ITL_Solver.hpp
@@ -456,7 +456,7 @@ namespace AMDiS
       // default iterative solver
       Map::addCreator("default", gmres);
 
-      init_direct(std::is_same<typename Dune::FieldTraits<T>::real_type, double>{});
+      init_direct(std::is_same<typename Dune::FieldTraits<typename Matrix::value_type>::real_type, double>{});
     }
 
     static void init_direct(std::false_type) {}
diff --git a/src/amdis/linearalgebra/mtl/UmfpackRunner.hpp b/src/amdis/linearalgebra/mtl/UmfpackRunner.hpp
index 546d25d0..368b3f41 100644
--- a/src/amdis/linearalgebra/mtl/UmfpackRunner.hpp
+++ b/src/amdis/linearalgebra/mtl/UmfpackRunner.hpp
@@ -48,7 +48,6 @@ namespace AMDiS
     /// Implementation of \ref RunnerInterface::init()
     void init(Matrix const& matrix, Comm&) override
     {
-      DUNE_UNUSED_PARAMETER(comm);
       try {
         solver_.reset(new SolverType(matrix, symmetricStrategy_, allocInit_));
       } catch (mtl::mat::umfpack::error const& e) {
diff --git a/src/amdis/utility/CMakeLists.txt b/src/amdis/utility/CMakeLists.txt
index 33add258..ec1450c4 100644
--- a/src/amdis/utility/CMakeLists.txt
+++ b/src/amdis/utility/CMakeLists.txt
@@ -4,5 +4,6 @@ install(FILES
     LocalToGlobalAdapter.hpp
     MacroGridFactory.hpp
     QuadratureFactory.hpp
+    Twist.hpp
     UniqueBorderPartition.hpp
 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/amdis/utility)
diff --git a/src/amdis/utility/Twist.hpp b/src/amdis/utility/Twist.hpp
new file mode 100644
index 00000000..d6ef68b1
--- /dev/null
+++ b/src/amdis/utility/Twist.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <vector>
+
+#include <dune/geometry/referenceelements.hh>
+#include <dune/localfunctions/common/localkey.hh>
+
+#include <amdis/Output.hpp>
+
+namespace AMDiS
+{
+  /// \brief Permutate the dof indices w.r.t. a global entity orientation
+  template <class IdSet, int dim>
+  class Twist
+  {
+    using IdType = typename IdSet::IdType;
+
+    using RefElements = typename Dune::ReferenceElements<double,dim>;
+    using RefElement = typename RefElements::ReferenceElement;
+
+  public:
+    /// Constructor. Stores a reference to the passed idSet
+    Twist(IdSet const& idSet)
+      : idSet_(idSet)
+    {}
+
+    /// Bind the twist to a codim-0 element. Calculates the global ids of all the element vertices.
+    template <class Element>
+    void bind(Element const& element)
+    {
+      static_assert(dim == Element::mydimension, "");
+      refElem_ = &RefElements::general(element.type());
+
+      ids_.resize(refElem_->size(dim));
+      for (int i = 0; i < refElem_->size(dim); ++i)
+        ids_[i] = idSet_.subId(element, i, dim);
+    }
+
+    /// Get the permutated local dof index, living on a subEntity of the bound element.
+    /**
+     * If the global entity orientation differs from the local orientation, perform a
+     * permutation of the local dof indices on that entity. This is currently implemented
+     * for edge entities only.
+     *
+     * \param localKey The Dune::LocalKey of the local dof, identifying the entity and local index
+     * \param size     The number of local dofs on that entity.
+     */
+    unsigned int get(Dune::LocalKey const& localKey, unsigned int size) const
+    {
+      int subDim = dim - localKey.codim();
+      if (subDim == 1 && 1 < dim) // facet == edge
+        return id(localKey,0) < id(localKey,1) ? localKey.index() : size - localKey.index() - 1;
+      else if (subDim == 2 && 2 < dim) { // facet == face
+        test_exit(size == 1, "Bases with more then one DoF per subentity are not yet supported.");
+        return localKey.index();
+      }
+
+      return localKey.index();
+    }
+
+  private:
+    IdType const& id(Dune::LocalKey const& localKey, int ii) const
+    {
+      return ids_[refElem_->subEntity(localKey.subEntity(), localKey.codim(), ii, dim)];
+    }
+
+  private:
+    IdSet const& idSet_;
+    RefElement const* refElem_ = nullptr;
+    std::vector<IdType> ids_;
+  };
+
+} // end namespace AMDiS
diff --git a/test/ISTLCommTest.cpp b/test/ISTLCommTest.cpp
index e3604680..16fcd63f 100644
--- a/test/ISTLCommTest.cpp
+++ b/test/ISTLCommTest.cpp
@@ -40,12 +40,15 @@ bool test(Basis& basis, std::string const& prefix)
 
   // Make communicator and exchange dofs
   auto comm = Comm::create(basis, prefix);
+
+#if HAVE_MPI
   comm->copyOwnerToAll(dofs, dofs);
 
   // Compare post-exchange data with reference
   for (std::size_t i = 0; i < dofs.size(); ++i)
     if (std::abs(dofs[i]-ref[i]) > AMDIS_TEST_TOL)
       passed = false;
+#endif
 
   return passed;
 }
-- 
GitLab