From f2be671f59790e80b5d759415fb657c7bebbeb75 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 29 Jun 2020 17:34:58 +0200
Subject: [PATCH] Generalize diamond dual mesh to 3D

---
 src/mesh/DiamondDualMeshBuilder.cpp | 210 ++++++++++++++++++----------
 src/mesh/DiamondDualMeshBuilder.hpp |   8 ++
 2 files changed, 148 insertions(+), 70 deletions(-)

diff --git a/src/mesh/DiamondDualMeshBuilder.cpp b/src/mesh/DiamondDualMeshBuilder.cpp
index 480693993..faa7f2779 100644
--- a/src/mesh/DiamondDualMeshBuilder.cpp
+++ b/src/mesh/DiamondDualMeshBuilder.cpp
@@ -12,32 +12,9 @@
 
 template <size_t Dimension>
 void
-DiamondDualMeshBuilder::_buildDiamondMeshFrom(const std::shared_ptr<const IMesh>&)
+DiamondDualMeshBuilder::_buildDiamondConnectivityDescriptor(const Connectivity<Dimension>& primal_connectivity,
+                                                            ConnectivityDescriptor& diamond_descriptor)
 {
-  static_assert(Dimension <= 3, "invalid mesh dimension");
-}
-
-template <>
-void
-DiamondDualMeshBuilder::_buildDiamondMeshFrom<1>(const std::shared_ptr<const IMesh>& p_mesh)
-{
-  m_mesh = p_mesh;
-}
-
-template <>
-void
-DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMesh>& p_mesh)
-{
-  m_mesh = p_mesh;
-
-  using MeshType = Mesh<Connectivity2D>;
-
-  const MeshType& primal_mesh = dynamic_cast<const MeshType&>(*p_mesh);
-
-  const Connectivity2D& primal_connectivity = primal_mesh.connectivity();
-
-  ConnectivityDescriptor diamond_descriptor;
-
   const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes();
   const size_t primal_number_of_cells = primal_connectivity.numberOfCells();
 
@@ -45,18 +22,19 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
 
   diamond_descriptor.node_number_vector.resize(diamond_number_of_nodes);
 
-  // const auto& primal_node_number = primal_connectivity.nodeNumber();
-  // const auto& primal_cell_number = primal_connectivity.cellNumber();
+  const auto& primal_node_number = primal_connectivity.nodeNumber();
+
+  for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) {
+    diamond_descriptor.node_number_vector[primal_node_id] = primal_node_number[primal_node_id];
+  }
 
-  // for (size_t i_primal_node = 0; i_primal_node < primal_connectivity.numberOfNodes(); ++i_primal_node) {
-  //   diamond_descriptor.node_number_vector[i_primal_node] = primal_node_number[i_primal_node];
-  // }
+  const auto& primal_cell_number = primal_connectivity.cellNumber();
 
-#warning fix max and compute diamond node numbers correctly in parallel
-  //  const size_t max_node_number =  max(primal_node_number);
+  const size_t max_node_number = max(primal_node_number);
 
-  for (size_t i = 0; i < diamond_number_of_nodes; ++i) {
-    diamond_descriptor.node_number_vector[i] = i;
+  for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) {
+    diamond_descriptor.node_number_vector[primal_number_of_nodes + primal_cell_id] =
+      primal_cell_number[primal_cell_id] + max_node_number;
   }
 
   const size_t diamond_number_of_cells = primal_connectivity.numberOfFaces();
@@ -78,11 +56,24 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
     const size_t i_cell               = i_face;
     const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face];
 
-    if (primal_face_cell_list.size() == 1) {
-      diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle;
+    if constexpr (Dimension == 1) {
+      throw NotImplementedError("dimension 1");
+    } else if constexpr (Dimension == 2) {
+      if (primal_face_cell_list.size() == 1) {
+        diamond_descriptor.cell_type_vector[i_cell] = CellType::Triangle;
+      } else {
+        Assert(primal_face_cell_list.size() == 2);
+        diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle;
+      }
     } else {
-      Assert(primal_face_cell_list.size() == 2);
-      diamond_descriptor.cell_type_vector[i_cell] = CellType::Quadrangle;
+      static_assert(Dimension == 3, "unexpected dimension");
+
+      if (primal_face_cell_list.size() == 1) {
+        diamond_descriptor.cell_type_vector[i_cell] = CellType::Pyramid;
+      } else {
+        Assert(primal_face_cell_list.size() == 2);
+        diamond_descriptor.cell_type_vector[i_cell] = CellType::Diamond;
+      }
     }
   }
 
@@ -96,43 +87,88 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
     const auto& primal_face_cell_list = primal_face_to_cell_matrix[i_face];
     const auto& primal_face_node_list = primal_face_to_node_matrix[i_face];
     if (primal_face_cell_list.size() == 1) {
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(3);
+      diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 1);
 
       const CellId cell_id      = primal_face_cell_list[0];
       const auto i_face_in_cell = primal_face_local_number_in_their_cells(i_face, 0);
 
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_face_node_list[0];
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = primal_face_node_list[1];
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][2] = primal_number_of_nodes + cell_id;
+      for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) {
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node] = primal_face_node_list[i_node];
+      }
+      diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size()] =
+        primal_number_of_nodes + cell_id;
 
       if (cell_face_is_reversed(cell_id, i_face_in_cell)) {
-        std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0],
-                  diamond_descriptor.cell_to_node_vector[i_diamond_cell][1]);
+        if constexpr (Dimension == 2) {
+          std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0],
+                    diamond_descriptor.cell_to_node_vector[i_diamond_cell][1]);
+
+        } else {
+          for (size_t i_node = 0; i_node < primal_face_node_list.size() / 2; ++i_node) {
+            std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node],
+                      diamond_descriptor
+                        .cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() - 1 - i_node]);
+          }
+        }
       }
     } else {
       Assert(primal_face_cell_list.size() == 2);
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(4);
+      diamond_descriptor.cell_to_node_vector[i_diamond_cell].resize(primal_face_node_list.size() + 2);
 
       const CellId cell0_id     = primal_face_cell_list[0];
       const CellId cell1_id     = primal_face_cell_list[1];
       const auto i_face_in_cell = primal_face_local_number_in_their_cells(i_face, 0);
 
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id;
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = primal_face_node_list[0];
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][2] = primal_number_of_nodes + cell1_id;
-      diamond_descriptor.cell_to_node_vector[i_diamond_cell][3] = primal_face_node_list[1];
+      if constexpr (Dimension == 2) {
+        Assert(primal_face_node_list.size() == 2);
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id;
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][1] = primal_face_node_list[0];
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][2] = primal_number_of_nodes + cell1_id;
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][3] = primal_face_node_list[1];
+
+        if (cell_face_is_reversed(cell0_id, i_face_in_cell)) {
+          std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][1],
+                    diamond_descriptor.cell_to_node_vector[i_diamond_cell][3]);
+        }
+      } else {
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][0] = primal_number_of_nodes + cell0_id;
+        for (size_t i_node = 0; i_node < primal_face_node_list.size(); ++i_node) {
+          diamond_descriptor.cell_to_node_vector[i_diamond_cell][i_node + 1] = primal_face_node_list[i_node];
+        }
+        diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1] =
+          primal_number_of_nodes + cell1_id;
 
-      if (cell_face_is_reversed(cell0_id, i_face_in_cell)) {
-        std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][1],
-                  diamond_descriptor.cell_to_node_vector[i_diamond_cell][3]);
+        if (cell_face_is_reversed(cell0_id, i_face_in_cell)) {
+          std::swap(diamond_descriptor.cell_to_node_vector[i_diamond_cell][0],
+                    diamond_descriptor.cell_to_node_vector[i_diamond_cell][primal_face_node_list.size() + 1]);
+        }
       }
     }
   }
+}
 
-  MeshBuilderBase::_computeCellFaceAndFaceNodeConnectivities<2>(diamond_descriptor);
+template <size_t Dimension>
+void
+DiamondDualMeshBuilder::_buildDiamondMeshFrom(const std::shared_ptr<const IMesh>& p_mesh)
+{
+  static_assert(Dimension <= 3, "invalid mesh dimension");
+  using ConnectivityType = Connectivity<Dimension>;
+  using MeshType         = Mesh<ConnectivityType>;
+
+  const MeshType& primal_mesh = dynamic_cast<const MeshType&>(*p_mesh);
+
+  const ConnectivityType& primal_connectivity = primal_mesh.connectivity();
+
+  ConnectivityDescriptor diamond_descriptor;
+
+  this->_buildDiamondConnectivityDescriptor(primal_connectivity, diamond_descriptor);
+
+  MeshBuilderBase::_computeCellFaceAndFaceNodeConnectivities<Dimension>(diamond_descriptor);
 
   {
-    using Face = ConnectivityFace<2>;
+    const auto& primal_face_to_node_matrix = primal_connectivity.faceToNodeMatrix();
+
+    using Face = ConnectivityFace<Dimension>;
 
     const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map = [&] {
       std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map;
@@ -144,9 +180,9 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
       return face_to_id_map;
     }();
 
-    for (size_t i_face_list = 0; i_face_list < primal_connectivity.numberOfRefItemList<ItemType::face>();
+    for (size_t i_face_list = 0; i_face_list < primal_connectivity.template numberOfRefItemList<ItemType::face>();
          ++i_face_list) {
-      const auto& primal_ref_face_list = primal_connectivity.refItemList<ItemType::face>(i_face_list);
+      const auto& primal_ref_face_list = primal_connectivity.template refItemList<ItemType::face>(i_face_list);
       std::cout << "treating " << primal_ref_face_list.refId() << '\n';
       const auto& primal_face_list = primal_ref_face_list.list();
 
@@ -183,24 +219,55 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
     }
   }
 
-#warning completly wrong
+  const size_t primal_number_of_nodes = primal_connectivity.numberOfNodes();
+  const size_t primal_number_of_cells = primal_connectivity.numberOfCells();
+
   diamond_descriptor.node_owner_vector.resize(diamond_descriptor.node_number_vector.size());
-  std::fill(diamond_descriptor.node_owner_vector.begin(), diamond_descriptor.node_owner_vector.end(), parallel::rank());
+
+  const auto& primal_node_owner = primal_connectivity.nodeOwner();
+  for (NodeId primal_node_id = 0; primal_node_id < primal_connectivity.numberOfNodes(); ++primal_node_id) {
+    diamond_descriptor.node_owner_vector[primal_node_id] = primal_node_owner[primal_node_id];
+  }
+  const auto& primal_cell_owner = primal_connectivity.cellOwner();
+  for (CellId primal_cell_id = 0; primal_cell_id < primal_number_of_cells; ++primal_cell_id) {
+    diamond_descriptor.node_owner_vector[primal_number_of_nodes + primal_cell_id] = primal_cell_owner[primal_cell_id];
+  }
 
   diamond_descriptor.cell_owner_vector.resize(diamond_descriptor.cell_number_vector.size());
-  std::fill(diamond_descriptor.cell_owner_vector.begin(), diamond_descriptor.cell_owner_vector.end(), parallel::rank());
+  const auto& primal_face_owner = primal_connectivity.faceOwner();
+  for (FaceId primal_face_id = 0; primal_face_id < primal_number_of_cells; ++primal_face_id) {
+    diamond_descriptor.cell_owner_vector[primal_face_id] = primal_face_owner[primal_face_id];
+  }
 
-  std::shared_ptr p_diamond_connectivity = Connectivity2D::build(diamond_descriptor);
-  Connectivity2D& diamond_connectivity   = *p_diamond_connectivity;
+  {
+    std::vector<int> face_cell_owner(diamond_descriptor.face_number_vector.size());
+    std::fill(std::begin(face_cell_owner), std::end(face_cell_owner), parallel::size());
+
+    for (size_t i_cell = 0; i_cell < diamond_descriptor.cell_to_face_vector.size(); ++i_cell) {
+      const auto& cell_face_list = diamond_descriptor.cell_to_face_vector[i_cell];
+      for (size_t i_face = 0; i_face < cell_face_list.size(); ++i_face) {
+        const size_t face_id     = cell_face_list[i_face];
+        face_cell_owner[face_id] = std::min(face_cell_owner[face_id], diamond_descriptor.cell_number_vector[i_cell]);
+      }
+    }
 
-  NodeValue<TinyVector<2>> diamond_xr{diamond_connectivity};
+    diamond_descriptor.face_owner_vector.resize(face_cell_owner.size());
+    for (size_t i_face = 0; i_face < face_cell_owner.size(); ++i_face) {
+      diamond_descriptor.face_owner_vector[i_face] = diamond_descriptor.cell_owner_vector[face_cell_owner[i_face]];
+    }
+  }
+
+  std::shared_ptr p_diamond_connectivity = ConnectivityType::build(diamond_descriptor);
+  ConnectivityType& diamond_connectivity = *p_diamond_connectivity;
+
+  NodeValue<TinyVector<Dimension>> diamond_xr{diamond_connectivity};
 
   const auto primal_xr = primal_mesh.xr();
-  MeshData<Mesh<Connectivity2D>> primal_mesh_data{primal_mesh};
+  MeshData<MeshType> primal_mesh_data{primal_mesh};
   const auto primal_xj = primal_mesh_data.xj();
 
   {
-#warning to recode
+#warning define transfer functions
     NodeId i_node = 0;
     for (; i_node < primal_number_of_nodes; ++i_node) {
       diamond_xr[i_node] = primal_xr[i_node];
@@ -211,9 +278,11 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
     }
   }
 
-  std::shared_ptr p_diamond_mesh = std::make_shared<Mesh<Connectivity2D>>(p_diamond_connectivity, diamond_xr);
+  std::shared_ptr p_diamond_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr);
 
-  MeshData<Mesh<Connectivity2D>> dual_mesh_data{*p_diamond_mesh};
+#warning USELESS TEST
+  // -->>
+  MeshData<MeshType> dual_mesh_data{*p_diamond_mesh};
 
   double sum = 0;
   for (CellId cell_id = 0; cell_id < p_diamond_mesh->numberOfCells(); ++cell_id) {
@@ -221,15 +290,16 @@ DiamondDualMeshBuilder::_buildDiamondMeshFrom<2>(const std::shared_ptr<const IMe
   }
 
   std::cout << "volume = " << sum << '\n';
+  // <<--
 
-  m_mesh = std::make_shared<Mesh<Connectivity2D>>(p_diamond_connectivity, diamond_xr);
+  m_mesh = std::make_shared<MeshType>(p_diamond_connectivity, diamond_xr);
 }
 
 template <>
-void
-DiamondDualMeshBuilder::_buildDiamondMeshFrom<3>(const std::shared_ptr<const IMesh>& p_mesh)
+[[deprecated]] void
+DiamondDualMeshBuilder::_buildDiamondMeshFrom<1>(const std::shared_ptr<const IMesh>&)
 {
-  m_mesh = p_mesh;
+  m_mesh = 0;
 }
 
 DiamondDualMeshBuilder::DiamondDualMeshBuilder(const std::shared_ptr<const IMesh>& p_mesh)
diff --git a/src/mesh/DiamondDualMeshBuilder.hpp b/src/mesh/DiamondDualMeshBuilder.hpp
index 7efbafa24..a6af1b830 100644
--- a/src/mesh/DiamondDualMeshBuilder.hpp
+++ b/src/mesh/DiamondDualMeshBuilder.hpp
@@ -6,9 +6,17 @@
 
 #include <memory>
 
+template <size_t>
+class Connectivity;
+
+class ConnectivityDescriptor;
+
 class DiamondDualMeshBuilder : public MeshBuilderBase
 {
  private:
+  template <size_t Dimension>
+  void _buildDiamondConnectivityDescriptor(const Connectivity<Dimension>&, ConnectivityDescriptor&);
+
   template <size_t Dimension>
   void _buildDiamondMeshFrom(const std::shared_ptr<const IMesh>&);
 
-- 
GitLab