From 9721b088b5158c770fb1f43089171718947ed9cf Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Tue, 9 Apr 2019 19:13:19 +0200
Subject: [PATCH] Manage edges in 3D

- building/reading of edges
- dispatching in parallel

This implies that [Sub]ItemValue<edge> are also now available
---
 src/mesh/Connectivity.cpp           |  60 +++-
 src/mesh/Connectivity.hpp           |  29 +-
 src/mesh/ConnectivityDispatcher.cpp |  50 ++-
 src/mesh/ConnectivityDispatcher.hpp |   1 +
 src/mesh/GmshReader.cpp             | 473 ++++++++++++++++++++--------
 src/mesh/GmshReader.hpp             |   3 +
 6 files changed, 465 insertions(+), 151 deletions(-)

diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp
index 5c9d59836..3a35c0255 100644
--- a/src/mesh/Connectivity.cpp
+++ b/src/mesh/Connectivity.cpp
@@ -54,7 +54,6 @@ _buildFrom(const ConnectivityDescriptor& descriptor)
     m_cell_global_index = cell_global_index;
   }
 
-
   {
     WeakCellValue<double> inv_cell_nb_nodes(*this);
     parallel_for(this->numberOfCells(), PASTIS_LAMBDA(const CellId& j) {
@@ -94,14 +93,13 @@ _buildFrom(const ConnectivityDescriptor& descriptor)
     m_node_is_owned = node_is_owned;
   }
 
+  m_ref_node_list_vector = descriptor.template refItemListVector<ItemType::node>();
+  m_ref_cell_list_vector = descriptor.template refItemListVector<ItemType::cell>();
+
   if constexpr (Dimension>1) {
-    auto& face_to_node_matrix
-        = m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)];
-    face_to_node_matrix = descriptor.face_to_node_vector;
+    m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)] = descriptor.face_to_node_vector;
 
-    auto& cell_to_face_matrix
-        = m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)];
-    cell_to_face_matrix = descriptor.cell_to_face_vector;
+    m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)] = descriptor.cell_to_face_vector;
 
     {
       FaceValuePerCell<bool> cell_face_is_reversed(*this);
@@ -111,14 +109,15 @@ _buildFrom(const ConnectivityDescriptor& descriptor)
           cell_face_is_reversed(j,lj) = face_cells_vector[lj];
         }
       }
-
       m_cell_face_is_reversed = cell_face_is_reversed;
     }
+
     {
       WeakFaceValue<int> face_number(*this);
       face_number = convert_to_array(descriptor.face_number_vector);
       m_face_number = face_number;
     }
+
     {
       WeakFaceValue<int> face_owner(*this);
       face_owner = convert_to_array(descriptor.face_owner_vector);
@@ -134,10 +133,49 @@ _buildFrom(const ConnectivityDescriptor& descriptor)
       m_face_is_owned = face_is_owned;
     }
 
-    m_ref_node_list_vector = descriptor.template refItemListVector<ItemType::node>();
-    m_ref_edge_list_vector = descriptor.template refItemListVector<ItemType::edge>();
     m_ref_face_list_vector = descriptor.template refItemListVector<ItemType::face>();
-    m_ref_cell_list_vector = descriptor.template refItemListVector<ItemType::cell>();
+
+    if constexpr (Dimension>2) {
+      m_item_to_item_matrix[itemTId(ItemType::edge)][itemTId(ItemType::node)] = descriptor.edge_to_node_vector;
+
+      m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::edge)] = descriptor.face_to_edge_vector;
+
+      m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::edge)] = descriptor.cell_to_edge_vector;
+
+      {
+        EdgeValuePerFace<bool> face_edge_is_reversed(*this);
+        for (FaceId l=0; l<descriptor.face_edge_is_reversed_vector.size(); ++l) {
+          const auto& edge_faces_vector = descriptor.face_edge_is_reversed_vector[l];
+          for (unsigned short el=0; el<edge_faces_vector.size(); ++el) {
+            face_edge_is_reversed(l,el) = edge_faces_vector[el];
+          }
+        }
+        m_face_edge_is_reversed = face_edge_is_reversed;
+      }
+
+      {
+        WeakEdgeValue<int> edge_number(*this);
+        edge_number = convert_to_array(descriptor.edge_number_vector);
+        m_edge_number = edge_number;
+      }
+
+      {
+        WeakEdgeValue<int> edge_owner(*this);
+        edge_owner = convert_to_array(descriptor.edge_owner_vector);
+        m_edge_owner = edge_owner;
+      }
+
+      {
+        const int rank = parallel::rank();
+        WeakEdgeValue<bool> edge_is_owned(*this);
+        parallel_for(this->numberOfEdges(), PASTIS_LAMBDA(const EdgeId& e) {
+            edge_is_owned[e] = (m_edge_owner[e] == rank);
+          });
+        m_edge_is_owned = edge_is_owned;
+      }
+
+      m_ref_edge_list_vector = descriptor.template refItemListVector<ItemType::edge>();
+    }
   }
 }
 
diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index 2a27cb380..098675884 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -48,14 +48,13 @@ class ConnectivityDescriptor
 
  public:
   std::vector<std::vector<unsigned int>> cell_to_node_vector;
-
-#warning should be set in 2d only
   std::vector<std::vector<unsigned int>> cell_to_face_vector;
-
-#warning should be set in 3d only
-  // std::vector<std::vector<unsigned int>> cell_to_edge_vector;
+  std::vector<std::vector<unsigned int>> cell_to_edge_vector;
 
   std::vector<std::vector<unsigned int>> face_to_node_vector;
+  std::vector<std::vector<unsigned int>> face_to_edge_vector;
+
+  std::vector<std::vector<unsigned int>> edge_to_node_vector;
 
   template <typename ItemOfItemT>
   auto& itemOfItemVector()
@@ -64,19 +63,27 @@ class ConnectivityDescriptor
       return cell_to_node_vector;
     } else if constexpr (std::is_same_v<ItemOfItemT,FaceOfCell>) {
       return cell_to_face_vector;
+    } else if constexpr (std::is_same_v<ItemOfItemT,EdgeOfCell>) {
+      return cell_to_edge_vector;
+    } else if constexpr (std::is_same_v<ItemOfItemT,EdgeOfFace>) {
+      return face_to_edge_vector;
     } else if constexpr (std::is_same_v<ItemOfItemT,NodeOfFace>) {
       return face_to_node_vector;
+    } else if constexpr (std::is_same_v<ItemOfItemT,NodeOfEdge>) {
+      return edge_to_node_vector;
     } else {
       static_assert(is_false_v<ItemOfItemT>, "Unexpected item of item type");
     }
   }
 
   std::vector<Array<bool>> cell_face_is_reversed_vector;
+  std::vector<Array<bool>> face_edge_is_reversed_vector;
 
   std::vector<CellType> cell_type_vector;
 
   std::vector<int> cell_number_vector;
   std::vector<int> face_number_vector;
+  std::vector<int> edge_number_vector;
   std::vector<int> node_number_vector;
 
   template <ItemType item_type>
@@ -86,6 +93,8 @@ class ConnectivityDescriptor
       return cell_number_vector;
     } else if constexpr (item_type == ItemType::face) {
       return face_number_vector;
+    } else if constexpr (item_type == ItemType::edge) {
+      return edge_number_vector;
     } else if constexpr (item_type == ItemType::node) {
       return node_number_vector;
     } else {
@@ -95,6 +104,7 @@ class ConnectivityDescriptor
 
   std::vector<int> cell_owner_vector;
   std::vector<int> face_owner_vector;
+  std::vector<int> edge_owner_vector;
   std::vector<int> node_owner_vector;
 
   template <ItemType item_type>
@@ -167,7 +177,6 @@ class Connectivity final
 
   WeakCellValue<const int> m_cell_number;
   WeakFaceValue<const int> m_face_number;
-#warning check that m_edge_number is filled correctly
   WeakEdgeValue<const int> m_edge_number;
   WeakNodeValue<const int> m_node_number;
 
@@ -184,6 +193,7 @@ class Connectivity final
   WeakNodeValue<const bool> m_node_is_owned;
 
   WeakFaceValuePerCell<const bool> m_cell_face_is_reversed;
+  WeakEdgeValuePerFace<const bool> m_face_edge_is_reversed;
 
   WeakNodeValuePerCell<const unsigned short> m_cell_local_numbers_in_their_nodes;
   WeakEdgeValuePerCell<const unsigned short> m_cell_local_numbers_in_their_edges;
@@ -474,6 +484,13 @@ class Connectivity final
     return m_cell_face_is_reversed;
   }
 
+  PASTIS_INLINE
+  const auto& faceEdgeIsReversed() const
+  {
+    static_assert(Dimension>2, "reversed edges makes no sense in dimension 1 or 2");
+    return m_face_edge_is_reversed;
+  }
+
   PASTIS_INLINE
   const auto& cellLocalNumbersInTheirNodes() const
   {
diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp
index 5b9fcdd4e..a21b316bd 100644
--- a/src/mesh/ConnectivityDispatcher.cpp
+++ b/src/mesh/ConnectivityDispatcher.cpp
@@ -431,6 +431,8 @@ ConnectivityDispatcher<Dimension>::_buildItemReferenceList()
           return number_of_item_list_sender;
         }();
 
+  pout() << "- dispatching references for " << itemName(item_type) << '\n';
+
   if (number_of_item_list_sender > 0) {
     if (number_of_item_list_sender > 1) {
       perr() << __FILE__ << ':' << __LINE__ << ": "
@@ -503,6 +505,10 @@ ConnectivityDispatcher<Dimension>::_buildItemReferenceList()
               return ref_id_list;
             } ();
 
+      for (auto ref_id : ref_id_list) {
+        pout() << "  - " << ref_id << '\n';
+      }
+
       using block_type = int32_t;
       constexpr size_t block_size = sizeof(block_type);
       const size_t nb_block = ref_id_list.size()/block_size + (ref_id_list.size()%block_size != 0);
@@ -575,13 +581,41 @@ ConnectivityDispatcher<Dimension>::_buildItemReferenceList()
 
           m_new_descriptor.addRefItemList(RefItemList<item_type>(ref_id_list[i_ref], item_id_array));
         }
-
-        pout() << __FILE__ << ':' << __LINE__ << ": remains to build lists\n";
       }
     }
   }
 }
 
+template <int Dimension>
+void
+ConnectivityDispatcher<Dimension>::_dispatchEdges()
+{
+  if constexpr (Dimension>2) {
+    this->_buildNumberOfSubItemPerItemToRecvByProc<EdgeOfCell>();
+    this->_buildSubItemNumbersToRecvByProc<EdgeOfCell>();
+    this->_buildSubItemNumberToIdMap<EdgeOfCell>();
+    this->_buildItemToExchangeLists<ItemType::edge>();
+
+    this->_gatherFrom(m_connectivity.template number<ItemType::edge>(), m_new_descriptor.edge_number_vector);
+
+    this->_buildItemToSubItemDescriptor<EdgeOfCell>();
+
+    this->_buildNumberOfSubItemPerItemToRecvByProc<NodeOfEdge>();
+    this->_buildSubItemNumbersToRecvByProc<NodeOfEdge>();
+    this->_buildItemToSubItemDescriptor<NodeOfEdge>();
+
+    this->_buildNumberOfSubItemPerItemToRecvByProc<EdgeOfFace>();
+    this->_buildSubItemNumbersToRecvByProc<EdgeOfFace>();
+    this->_buildItemToSubItemDescriptor<EdgeOfFace>();
+
+    this->_gatherFrom(m_connectivity.faceEdgeIsReversed(), m_new_descriptor.face_edge_is_reversed_vector);
+
+    this->_gatherFrom(this->_dispatchedInfo<ItemType::edge>().m_new_owner, m_new_descriptor.edge_owner_vector);
+
+    this->_buildItemReferenceList<ItemType::edge>();
+  }
+}
+
 template <int Dimension>
 void
 ConnectivityDispatcher<Dimension>::_dispatchFaces()
@@ -592,6 +626,10 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
     this->_buildSubItemNumberToIdMap<FaceOfCell>();
     this->_buildItemToExchangeLists<ItemType::face>();
 
+    this->_buildNumberOfSubItemPerItemToRecvByProc<NodeOfFace>();
+    this->_buildSubItemNumbersToRecvByProc<NodeOfFace>();
+    this->_buildItemToSubItemDescriptor<NodeOfFace>();
+
     this->_gatherFrom(m_connectivity.template number<ItemType::face>(), m_new_descriptor.face_number_vector);
 
     this->_buildItemToSubItemDescriptor<FaceOfCell>();
@@ -600,10 +638,6 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
     this->_gatherFrom(this->_dispatchedInfo<ItemType::face>().m_new_owner, m_new_descriptor.face_owner_vector);
 
-    this->_buildNumberOfSubItemPerItemToRecvByProc<NodeOfFace>();
-    this->_buildSubItemNumbersToRecvByProc<NodeOfFace>();
-    this->_buildItemToSubItemDescriptor<NodeOfFace>();
-
     this->_buildItemReferenceList<ItemType::face>();
   }
 }
@@ -615,7 +649,7 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
 {
   this->_buildNewOwner<ItemType::cell>();
   this->_buildNewOwner<ItemType::face>();
-  // this->_buildNewOwner<ItemType::edge>();
+  this->_buildNewOwner<ItemType::edge>();
   this->_buildNewOwner<ItemType::node>();
 
   this->_buildItemToExchangeLists<ItemType::cell>();
@@ -643,6 +677,8 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
 
   this->_dispatchFaces();
 
+  this->_dispatchEdges();
+
   this->_buildItemReferenceList<ItemType::node>();
 
   m_dispatched_connectivity = ConnectivityType::build(m_new_descriptor);
diff --git a/src/mesh/ConnectivityDispatcher.hpp b/src/mesh/ConnectivityDispatcher.hpp
index d6a97afcb..710f336a9 100644
--- a/src/mesh/ConnectivityDispatcher.hpp
+++ b/src/mesh/ConnectivityDispatcher.hpp
@@ -174,6 +174,7 @@ class ConnectivityDispatcher
   template <typename ItemOfItemT>
   void _buildItemToSubItemDescriptor();
 
+  void _dispatchEdges();
   void _dispatchFaces();
 
   template<typename DataType, ItemType item_type, typename ConnectivityPtr>
diff --git a/src/mesh/GmshReader.cpp b/src/mesh/GmshReader.cpp
index d1e4e5412..2817d7a3d 100644
--- a/src/mesh/GmshReader.cpp
+++ b/src/mesh/GmshReader.cpp
@@ -937,7 +937,7 @@ GmshReader::__computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& d
     for (const auto& face_cells_vector : face_cells_map) {
       const auto& cells_vector = face_cells_vector.second;
       for (unsigned short lj=0; lj<cells_vector.size(); ++lj) {
-        const auto& [cell_number, cell_local_face, reversed] = cells_vector[lj];
+        const auto& [cell_number, cell_local_face,  reversed] = cells_vector[lj];
         descriptor.cell_to_face_vector[cell_number][cell_local_face] = l;
       }
       ++l;
@@ -978,6 +978,134 @@ GmshReader::__computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& d
 }
 
 
+template <size_t Dimension>
+void
+GmshReader::__computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor)
+{
+  static_assert(Dimension==3, "Invalid dimension to compute face-edge connectivities");
+  using FaceEdgeInfo = std::tuple<FaceId, unsigned short, bool>;
+  using Edge = ConnectivityFace<2>;
+
+  const auto& node_number_vector = descriptor.node_number_vector;
+  Array<unsigned short> face_nb_edges(descriptor.face_to_node_vector.size());
+  std::map<Edge, std::vector<FaceEdgeInfo>> edge_faces_map;
+  for (FaceId l=0; l<descriptor.face_to_node_vector.size(); ++l) {
+    const auto& face_nodes = descriptor.face_to_node_vector[l];
+
+    face_nb_edges[l] = face_nodes.size();
+    for (size_t r=0; r<face_nodes.size()-1; ++r) {
+      Edge e({face_nodes[r], face_nodes[r+1]}, node_number_vector);
+      edge_faces_map[e].emplace_back(std::make_tuple(l, r, e.reversed()));
+    }
+    {
+      Edge e({face_nodes[face_nodes.size()-1], face_nodes[0]}, node_number_vector);
+      edge_faces_map[e].emplace_back(std::make_tuple(l, face_nodes.size()-1, e.reversed()));
+    }
+  }
+
+  std::unordered_map<Edge,EdgeId,typename Edge::Hash> edge_id_map;
+  {
+    descriptor.face_to_edge_vector.resize(descriptor.face_to_node_vector.size());
+    for (FaceId l=0; l<descriptor.face_to_node_vector.size(); ++l) {
+      descriptor.face_to_edge_vector[l].resize(face_nb_edges[l]);
+    }
+    EdgeId e=0;
+    for (const auto& edge_faces_vector : edge_faces_map) {
+      const auto& faces_vector = edge_faces_vector.second;
+      for (unsigned short l=0; l<faces_vector.size(); ++l) {
+        const auto& [face_number, face_local_edge,  reversed] = faces_vector[l];
+        descriptor.face_to_edge_vector[face_number][face_local_edge] = e;
+      }
+      edge_id_map[edge_faces_vector.first] = e;
+      ++e;
+    }
+  }
+
+  {
+    descriptor.face_edge_is_reversed_vector.resize(descriptor.face_to_node_vector.size());
+    for (FaceId j=0; j<descriptor.face_edge_is_reversed_vector.size(); ++j) {
+      descriptor.face_edge_is_reversed_vector[j] = Array<bool>(face_nb_edges[j]);
+    }
+    for (const auto& edge_faces_vector : edge_faces_map) {
+      const auto& faces_vector = edge_faces_vector.second;
+      for (unsigned short lj=0; lj<faces_vector.size(); ++lj) {
+        const auto& [face_number, face_local_edge, reversed] = faces_vector[lj];
+        descriptor.face_edge_is_reversed_vector[face_number][face_local_edge] = reversed;
+      }
+    }
+  }
+
+  {
+    descriptor.edge_to_node_vector.resize(edge_faces_map.size());
+    int e=0;
+    for (const auto& edge_info : edge_faces_map) {
+      const Edge& edge = edge_info.first;
+      descriptor.edge_to_node_vector[e] = edge.nodeIdList();
+      ++e;
+    }
+  }
+
+  {
+    // Edge numbers may change if numbers are provided in the file
+    descriptor.edge_number_vector.resize(edge_faces_map.size());
+    for (size_t e=0; e<edge_faces_map.size(); ++e) {
+      descriptor.edge_number_vector[e] = e;
+    }
+  }
+
+  {
+    descriptor.cell_to_node_vector.reserve(descriptor.cell_to_node_vector.size());
+    for (CellId j=0; j<descriptor.cell_to_node_vector.size(); ++j) {
+      const auto& cell_nodes = descriptor.cell_to_node_vector[j];
+
+      switch (descriptor.cell_type_vector[j]) {
+      case CellType::Tetrahedron: {
+        constexpr int local_edge[6][2] = {{0,1}, {0,2}, {0,3}, {1,2}, {2,3}, {3,1}};
+        std::vector<unsigned int> cell_edge_vector;
+        cell_edge_vector.reserve(6);
+        for (int i_edge=0; i_edge<6; ++i_edge) {
+          const auto e = local_edge[i_edge];
+          Edge edge{{cell_nodes[e[0]],cell_nodes[e[1]]}, node_number_vector};
+          auto i = edge_id_map.find(edge);
+          if (i == edge_id_map.end()) {
+            std::cerr << "could not find this edge!\n";
+            std::terminate();
+          }
+          cell_edge_vector.push_back(i->second);
+        }
+        descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector);
+        break;
+      }
+      case CellType::Hexahedron: {
+        constexpr int local_edge[12][2] = {{0,1}, {1,2}, {2,3}, {3,0},
+                                           {4,5}, {5,6}, {6,7}, {7,4},
+                                           {0,4}, {1,5}, {2,6}, {3,7}};
+        std::vector<unsigned int> cell_edge_vector;
+        cell_edge_vector.reserve(12);
+        for (int i_edge=0; i_edge<12; ++i_edge) {
+          const auto e = local_edge[i_edge];
+          Edge edge{{cell_nodes[e[0]],cell_nodes[e[1]]}, node_number_vector};
+          auto i = edge_id_map.find(edge);
+          if (i == edge_id_map.end()) {
+            std::cerr << "could not find this edge!\n";
+            std::terminate();
+          }
+          cell_edge_vector.push_back(i->second);
+        }
+        descriptor.cell_to_edge_vector.emplace_back(cell_edge_vector);
+        break;
+      }
+      default: {
+        perr() << name(descriptor.cell_type_vector[j])
+               << ": unexpected cell type in dimension 3!\n";
+        std::terminate();
+      }
+      }
+    }
+  }
+}
+
+
 void
 GmshReader::__proceedData()
 {
@@ -1308,126 +1436,217 @@ GmshReader::__proceedData()
       descriptor.addRefItemList(RefCellList(physical_ref_id.refId(), cell_list));
     }
 
-    __computeCellFaceAndFaceNodeConnectivities<3>(descriptor);
-
-    descriptor.cell_owner_vector.resize(nb_cells);
-    std::fill(descriptor.cell_owner_vector.begin(),
-              descriptor.cell_owner_vector.end(),
-              parallel::rank());
-
-    descriptor.face_owner_vector.resize(descriptor.face_number_vector.size());
-    std::fill(descriptor.face_owner_vector.begin(),
-              descriptor.face_owner_vector.end(),
-              parallel::rank());
-
-    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
-    std::fill(descriptor.node_owner_vector.begin(),
-              descriptor.node_owner_vector.end(),
-              parallel::rank());
+    this->__computeCellFaceAndFaceNodeConnectivities<3>(descriptor);
 
     const auto& node_number_vector = descriptor.node_number_vector;
 
-    using Face = ConnectivityFace<3>;
-    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;
-            for (FaceId l=0; l<descriptor.face_to_node_vector.size(); ++l) {
-              const auto& node_vector = descriptor.face_to_node_vector[l];
-              face_to_id_map[Face(node_vector, node_number_vector)] = l;
-            }
-            return face_to_id_map;
-          } ();
-
-    std::unordered_map<int, FaceId> face_number_id_map
-        = [&] {
-            std::unordered_map<int, FaceId> face_number_id_map;
-            for (size_t l=0; l< descriptor.face_number_vector.size(); ++l) {
-              face_number_id_map[descriptor.face_number_vector[l]] = l;
-            }
-            Assert(face_number_id_map.size() == descriptor.face_number_vector.size());
-            return face_number_id_map;
-          } ();
-
-    std::map<unsigned int, std::vector<unsigned int>> ref_faces_map;
-    for (unsigned int f=0; f<__triangles.size(); ++f) {
-      const unsigned int face_id
-          = [&]{
-              auto i = face_to_id_map.find(Face({__triangles[f][0], __triangles[f][1], __triangles[f][2]},
-                                                node_number_vector));
-              if (i == face_to_id_map.end()) {
-                std::cerr << "face not found!\n";
-                std::terminate();
+    {
+      using Face = ConnectivityFace<3>;
+      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;
+              for (FaceId l=0; l<descriptor.face_to_node_vector.size(); ++l) {
+                const auto& node_vector = descriptor.face_to_node_vector[l];
+                face_to_id_map[Face(node_vector, node_number_vector)] = l;
               }
-              return i->second;
-            }();
-
-      const unsigned int& ref = __triangles_ref[f];
-      ref_faces_map[ref].push_back(face_id);
-
-      if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) {
-        if (auto i_face = face_number_id_map.find(__quadrangles_number[f]);
-            i_face != face_number_id_map.end()) {
-          const int other_face_id = i_face->second;
-          std::swap(descriptor.face_number_vector[face_id],
-                    descriptor.face_number_vector[other_face_id]);
+              return face_to_id_map;
+            } ();
+
+      std::unordered_map<int, FaceId> face_number_id_map
+          = [&] {
+              std::unordered_map<int, FaceId> face_number_id_map;
+              for (size_t l=0; l< descriptor.face_number_vector.size(); ++l) {
+                face_number_id_map[descriptor.face_number_vector[l]] = l;
+              }
+              Assert(face_number_id_map.size() == descriptor.face_number_vector.size());
+              return face_number_id_map;
+            } ();
+
+      std::map<unsigned int, std::vector<unsigned int>> ref_faces_map;
+      for (unsigned int f=0; f<__triangles.size(); ++f) {
+        const unsigned int face_id
+            = [&]{
+                auto i = face_to_id_map.find(Face({__triangles[f][0], __triangles[f][1], __triangles[f][2]},
+                                                  node_number_vector));
+                if (i == face_to_id_map.end()) {
+                  std::cerr << "face not found!\n";
+                  std::terminate();
+                }
+                return i->second;
+              }();
+
+        const unsigned int& ref = __triangles_ref[f];
+        ref_faces_map[ref].push_back(face_id);
+
+        if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) {
+          if (auto i_face = face_number_id_map.find(__quadrangles_number[f]);
+              i_face != face_number_id_map.end()) {
+            const int other_face_id = i_face->second;
+            std::swap(descriptor.face_number_vector[face_id],
+                      descriptor.face_number_vector[other_face_id]);
+
+            face_number_id_map.erase(descriptor.face_number_vector[face_id]);
+            face_number_id_map.erase(descriptor.face_number_vector[other_face_id]);
+
+            face_number_id_map[descriptor.face_number_vector[face_id]]=face_id;
+            face_number_id_map[descriptor.face_number_vector[other_face_id]]=other_face_id;
+          } else {
+            face_number_id_map.erase(descriptor.face_number_vector[face_id]);
+            descriptor.face_number_vector[face_id] = __quadrangles_number[f];
+            face_number_id_map[descriptor.face_number_vector[face_id]] = face_id;
+          }
+        }
+      }
 
-          face_number_id_map.erase(descriptor.face_number_vector[face_id]);
-          face_number_id_map.erase(descriptor.face_number_vector[other_face_id]);
+      for (unsigned int f=0; f<__quadrangles.size(); ++f) {
+        const unsigned int face_id
+            = [&]{
+                auto i = face_to_id_map.find(Face({__quadrangles[f][0], __quadrangles[f][1],
+                                                   __quadrangles[f][2], __quadrangles[f][3]}, node_number_vector));
+                if (i == face_to_id_map.end()) {
+                  std::cerr << "face not found!\n";
+                  std::terminate();
+                }
+                return i->second;
+              }();
+
+        const unsigned int& ref = __quadrangles_ref[f];
+        ref_faces_map[ref].push_back(face_id);
+
+        if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) {
+          if (auto i_face = face_number_id_map.find(__quadrangles_number[f]);
+              i_face != face_number_id_map.end()) {
+            const int other_face_id = i_face->second;
+            std::swap(descriptor.face_number_vector[face_id],
+                      descriptor.face_number_vector[other_face_id]);
+
+            face_number_id_map.erase(descriptor.face_number_vector[face_id]);
+            face_number_id_map.erase(descriptor.face_number_vector[other_face_id]);
+
+            face_number_id_map[descriptor.face_number_vector[face_id]]=face_id;
+            face_number_id_map[descriptor.face_number_vector[other_face_id]]=other_face_id;
+          } else {
+            face_number_id_map.erase(descriptor.face_number_vector[face_id]);
+            descriptor.face_number_vector[face_id] = __quadrangles_number[f];
+            face_number_id_map[descriptor.face_number_vector[face_id]] = face_id;
+          }
+        }
+      }
 
-          face_number_id_map[descriptor.face_number_vector[face_id]]=face_id;
-          face_number_id_map[descriptor.face_number_vector[other_face_id]]=other_face_id;
-        } else {
-          face_number_id_map.erase(descriptor.face_number_vector[face_id]);
-          descriptor.face_number_vector[face_id] = __quadrangles_number[f];
-          face_number_id_map[descriptor.face_number_vector[face_id]] = face_id;
+      for (const auto& ref_face_list : ref_faces_map) {
+        Array<FaceId> face_list(ref_face_list.second.size());
+        for (size_t j=0; j<ref_face_list.second.size(); ++j) {
+          face_list[j]=ref_face_list.second[j];
         }
+        const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_face_list.first);
+        descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list});
       }
     }
-
-    for (unsigned int f=0; f<__quadrangles.size(); ++f) {
-      const unsigned int face_id
-          = [&]{
-              auto i = face_to_id_map.find(Face({__quadrangles[f][0], __quadrangles[f][1],
-                                                 __quadrangles[f][2], __quadrangles[f][3]}, node_number_vector));
-              if (i == face_to_id_map.end()) {
-                std::cerr << "face not found!\n";
-                std::terminate();
+    this->__computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities<3>(descriptor);
+
+    {
+      using Edge = ConnectivityFace<2>;
+      const auto& node_number_vector = descriptor.node_number_vector;
+      const std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map
+          = [&]  {
+              std::unordered_map<Edge, EdgeId, typename Edge::Hash> edge_to_id_map;
+              for (EdgeId l=0; l<descriptor.edge_to_node_vector.size(); ++l) {
+                const auto& node_vector = descriptor.edge_to_node_vector[l];
+                edge_to_id_map[Edge(node_vector, node_number_vector)] = l;
               }
-              return i->second;
-            }();
-
-      const unsigned int& ref = __quadrangles_ref[f];
-      ref_faces_map[ref].push_back(face_id);
-
-      if (descriptor.face_number_vector[face_id] != __quadrangles_number[f]) {
-        if (auto i_face = face_number_id_map.find(__quadrangles_number[f]);
-            i_face != face_number_id_map.end()) {
-          const int other_face_id = i_face->second;
-          std::swap(descriptor.face_number_vector[face_id],
-                    descriptor.face_number_vector[other_face_id]);
-
-          face_number_id_map.erase(descriptor.face_number_vector[face_id]);
-          face_number_id_map.erase(descriptor.face_number_vector[other_face_id]);
+              return edge_to_id_map;
+            } ();
+
+      std::unordered_map<int, EdgeId> edge_number_id_map
+          = [&] {
+              std::unordered_map<int, EdgeId> edge_number_id_map;
+              for (size_t l=0; l< descriptor.edge_number_vector.size(); ++l) {
+                edge_number_id_map[descriptor.edge_number_vector[l]] = l;
+              }
+              Assert(edge_number_id_map.size() == descriptor.edge_number_vector.size());
+              return edge_number_id_map;
+            } ();
+
+      std::map<unsigned int, std::vector<unsigned int>> ref_edges_map;
+      for (unsigned int e=0; e<__edges.size(); ++e) {
+        const unsigned int edge_id
+            = [&]{
+                auto i = edge_to_id_map.find(Edge({__edges[e][0], __edges[e][1]}, node_number_vector));
+                if (i == edge_to_id_map.end()) {
+                  std::cerr << "edge " << __edges[e][0] << " not found!\n";
+                  std::terminate();
+                }
+                return i->second;
+              }();
+        const unsigned int& ref = __edges_ref[e];
+        ref_edges_map[ref].push_back(edge_id);
+
+        if (descriptor.edge_number_vector[edge_id] != __edges_number[e]) {
+          if (auto i_edge = edge_number_id_map.find(__edges_number[e]);
+              i_edge != edge_number_id_map.end()) {
+            const int other_edge_id = i_edge->second;
+            std::swap(descriptor.edge_number_vector[edge_id],
+                      descriptor.edge_number_vector[other_edge_id]);
+
+            edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]);
+            edge_number_id_map.erase(descriptor.edge_number_vector[other_edge_id]);
+
+            edge_number_id_map[descriptor.edge_number_vector[edge_id]]=edge_id;
+            edge_number_id_map[descriptor.edge_number_vector[other_edge_id]]=other_edge_id;
+          } else {
+            edge_number_id_map.erase(descriptor.edge_number_vector[edge_id]);
+            descriptor.edge_number_vector[edge_id] = __edges_number[e];
+            edge_number_id_map[descriptor.edge_number_vector[edge_id]] = edge_id;
+          }
+        }
+      }
 
-          face_number_id_map[descriptor.face_number_vector[face_id]]=face_id;
-          face_number_id_map[descriptor.face_number_vector[other_face_id]]=other_face_id;
-        } else {
-          face_number_id_map.erase(descriptor.face_number_vector[face_id]);
-          descriptor.face_number_vector[face_id] = __quadrangles_number[f];
-          face_number_id_map[descriptor.face_number_vector[face_id]] = face_id;
+      for (const auto& ref_edge_list : ref_edges_map) {
+        Array<EdgeId> edge_list(ref_edge_list.second.size());
+        for (size_t j=0; j<ref_edge_list.second.size(); ++j) {
+          edge_list[j]=ref_edge_list.second[j];
         }
+        const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_edge_list.first);
+        descriptor.addRefItemList(RefEdgeList{physical_ref_id.refId(), edge_list});
       }
     }
 
-    for (const auto& ref_face_list : ref_faces_map) {
-      Array<FaceId> face_list(ref_face_list.second.size());
-      for (size_t j=0; j<ref_face_list.second.size(); ++j) {
-        face_list[j]=ref_face_list.second[j];
+    std::map<unsigned int, std::vector<unsigned int>> ref_points_map;
+    for (unsigned int r=0; r<__points.size(); ++r) {
+      const unsigned int point_number = __points[r];
+      const unsigned int& ref = __points_ref[r];
+      ref_points_map[ref].push_back(point_number);
+    }
+
+    for (const auto& ref_point_list : ref_points_map) {
+      Array<NodeId> point_list(ref_point_list.second.size());
+      for (size_t j=0; j<ref_point_list.second.size(); ++j) {
+        point_list[j]=ref_point_list.second[j];
       }
-      const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_face_list.first);
-      descriptor.addRefItemList(RefFaceList{physical_ref_id.refId(), face_list});
+      const PhysicalRefId& physical_ref_id = m_physical_ref_map.at(ref_point_list.first);
+      descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list));
     }
 
+    descriptor.cell_owner_vector.resize(nb_cells);
+    std::fill(descriptor.cell_owner_vector.begin(),
+              descriptor.cell_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.face_owner_vector.resize(descriptor.face_number_vector.size());
+    std::fill(descriptor.face_owner_vector.begin(),
+              descriptor.face_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.edge_owner_vector.resize(descriptor.edge_number_vector.size());
+    std::fill(descriptor.edge_owner_vector.begin(),
+              descriptor.edge_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
+    std::fill(descriptor.node_owner_vector.begin(),
+              descriptor.node_owner_vector.end(),
+              parallel::rank());
+
     std::shared_ptr p_connectivity = Connectivity3D::build(descriptor);
     Connectivity3D& connectivity = *p_connectivity;
 
@@ -1497,21 +1716,6 @@ GmshReader::__proceedData()
 
     this->__computeCellFaceAndFaceNodeConnectivities<2>(descriptor);
 
-    descriptor.cell_owner_vector.resize(nb_cells);
-    std::fill(descriptor.cell_owner_vector.begin(),
-              descriptor.cell_owner_vector.end(),
-              parallel::rank());
-
-    descriptor.face_owner_vector.resize(descriptor.face_number_vector.size());
-    std::fill(descriptor.face_owner_vector.begin(),
-              descriptor.face_owner_vector.end(),
-              parallel::rank());
-
-    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
-    std::fill(descriptor.node_owner_vector.begin(),
-              descriptor.node_owner_vector.end(),
-              parallel::rank());
-
     using Face = ConnectivityFace<2>;
     const auto& node_number_vector = descriptor.node_number_vector;
     const std::unordered_map<Face, FaceId, typename Face::Hash> face_to_id_map
@@ -1593,6 +1797,20 @@ GmshReader::__proceedData()
       descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list));
     }
 
+    descriptor.cell_owner_vector.resize(nb_cells);
+    std::fill(descriptor.cell_owner_vector.begin(),
+              descriptor.cell_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.face_owner_vector.resize(descriptor.face_number_vector.size());
+    std::fill(descriptor.face_owner_vector.begin(),
+              descriptor.face_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
+    std::fill(descriptor.node_owner_vector.begin(),
+              descriptor.node_owner_vector.end(),
+              parallel::rank());
 
     std::shared_ptr p_connectivity = Connectivity2D::build(descriptor);
     Connectivity2D& connectivity = *p_connectivity;
@@ -1626,15 +1844,6 @@ GmshReader::__proceedData()
       descriptor.cell_number_vector[j] =  __edges_number[j];
     }
 
-    descriptor.cell_owner_vector.resize(nb_cells);
-    std::fill(descriptor.cell_owner_vector.begin(),
-              descriptor.cell_owner_vector.end(),
-              parallel::rank());
-
-    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
-    std::fill(descriptor.node_owner_vector.begin(),
-              descriptor.node_owner_vector.end(),
-              parallel::rank());
 
     std::map<unsigned int, std::vector<unsigned int>> ref_points_map;
     for (unsigned int r=0; r<__points.size(); ++r) {
@@ -1652,6 +1861,16 @@ GmshReader::__proceedData()
       descriptor.addRefItemList(RefNodeList(physical_ref_id.refId(), point_list));
     }
 
+    descriptor.cell_owner_vector.resize(nb_cells);
+    std::fill(descriptor.cell_owner_vector.begin(),
+              descriptor.cell_owner_vector.end(),
+              parallel::rank());
+
+    descriptor.node_owner_vector.resize(descriptor.node_number_vector.size());
+    std::fill(descriptor.node_owner_vector.begin(),
+              descriptor.node_owner_vector.end(),
+              parallel::rank());
+
     std::shared_ptr p_connectivity = Connectivity1D::build(descriptor);
     Connectivity1D& connectivity = *p_connectivity;
 
diff --git a/src/mesh/GmshReader.hpp b/src/mesh/GmshReader.hpp
index 1ddb6c4db..cd482e637 100644
--- a/src/mesh/GmshReader.hpp
+++ b/src/mesh/GmshReader.hpp
@@ -262,6 +262,9 @@ private:
   template <size_t Dimension>
   void __computeCellFaceAndFaceNodeConnectivities(ConnectivityDescriptor& descriptor);
 
+  template <size_t Dimension>
+  void __computeFaceEdgeAndEdgeNodeAndCellEdgeConnectivities(ConnectivityDescriptor& descriptor);
+
   template <int Dimension>
   void _dispatch();
 
-- 
GitLab