From b7082fe981a3a8f47d84ee836bc0d7e094b65792 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Fri, 15 Mar 2019 19:19:18 +0100
Subject: [PATCH] Continue clean-up in mesh dispatcher

---
 src/mesh/ConnectivityDispatcher.cpp | 583 ++++++++++++++--------------
 src/mesh/ConnectivityDispatcher.hpp | 165 ++++----
 src/mesh/SubItemOfItemType.hpp      |  32 ++
 3 files changed, 425 insertions(+), 355 deletions(-)
 create mode 100644 src/mesh/SubItemOfItemType.hpp

diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp
index dcabf13c6..f88f596f1 100644
--- a/src/mesh/ConnectivityDispatcher.cpp
+++ b/src/mesh/ConnectivityDispatcher.cpp
@@ -1,82 +1,63 @@
 #include <ConnectivityDispatcher.hpp>
 #include <Partitioner.hpp>
 
+#include <SubItemOfItemType.hpp>
+
 #include <unordered_map>
 
 template <int Dimension>
-CellValue<int>
-ConnectivityDispatcher<Dimension>::_getCellNewOwner()
+template <ItemType item_type>
+void
+ConnectivityDispatcher<Dimension>::_buildNewOwner()
 {
-  CSRGraph connectivity_graph = m_connectivity.cellToCellGraph();
-  Partitioner P;
+  if constexpr (item_type == ItemType::cell) {
+    CSRGraph connectivity_graph = m_connectivity.cellToCellGraph();
+    Partitioner P;
 
-  CellValue<int> cell_new_owner(m_connectivity);
-  cell_new_owner = P.partition(connectivity_graph);
-  return cell_new_owner;
-}
+    CellValue<int> cell_new_owner(m_connectivity);
+    cell_new_owner = P.partition(connectivity_graph);
 
-template <int Dimension>
-FaceValue<int>
-ConnectivityDispatcher<Dimension>::_getFaceNewOwner()
-{
-  const auto& face_to_cell_matrix
-      = m_connectivity.faceToCellMatrix();
-  const auto& cell_number = m_connectivity.cellNumber();
-
-  FaceValue<int> face_new_owner(m_connectivity);
-  parallel_for(m_connectivity.numberOfFaces(), PASTIS_LAMBDA(const FaceId& l) {
-      const auto& face_to_cell = face_to_cell_matrix[l];
-      CellId Jmin = face_to_cell[0];
-
-      for (size_t j=1; j<face_to_cell.size(); ++j) {
-        const CellId J = face_to_cell[j];
-        if (cell_number[J] < cell_number[Jmin]) {
-          Jmin=J;
-        }
-      }
-      face_new_owner[l] = m_cell_new_owner[Jmin];
-    });
+    this->_dispatchedInfo<ItemType::cell>().m_new_owner = cell_new_owner;
+  } else {
+    const auto& item_to_cell_matrix
+        = m_connectivity.template getItemToItemMatrix<item_type,ItemType::cell>();
 
-#warning Add missing synchronize (fix it!)
-  //  synchronize(face_new_owner);
-  return face_new_owner;
-}
+    const auto& cell_number = m_connectivity.cellNumber();
 
-template <int Dimension>
-NodeValue<int>
-ConnectivityDispatcher<Dimension>::_getNodeNewOwner()
-{
-  const auto& node_to_cell_matrix = m_connectivity.nodeToCellMatrix();
-  const auto& cell_number = m_connectivity.cellNumber();
+    const auto& cell_new_owner = this->_dispatchedInfo<ItemType::cell>().m_new_owner;
 
-  NodeValue<int> node_new_owner(m_connectivity);
-  parallel_for(m_connectivity.numberOfNodes(), PASTIS_LAMBDA(const NodeId& r) {
-      const auto& node_to_cell = node_to_cell_matrix[r];
-      CellId Jmin = node_to_cell[0];
+    using ItemId = ItemIdT<item_type>;
+    ItemValue<int, item_type> item_new_owner(m_connectivity);
+    parallel_for(item_new_owner.size(), PASTIS_LAMBDA(const ItemId& l) {
+        const auto& item_to_cell = item_to_cell_matrix[l];
+        CellId Jmin = item_to_cell[0];
 
-      for (size_t j=1; j<node_to_cell.size(); ++j) {
-        const CellId J = node_to_cell[j];
-        if (cell_number[J] < cell_number[Jmin]) {
-          Jmin=J;
+        for (size_t j=1; j<item_to_cell.size(); ++j) {
+          const CellId J = item_to_cell[j];
+          if (cell_number[J] < cell_number[Jmin]) {
+            Jmin=J;
+          }
         }
-      }
-      node_new_owner[r] = m_cell_new_owner[Jmin];
-    });
+        item_new_owner[l] = cell_new_owner[Jmin];
+      });
 
 #warning Add missing synchronize (fix it!)
-  //  synchronize(node_new_owner);
-  return node_new_owner;
+    // synchronize(face_new_owner);
+    this->_dispatchedInfo<item_type>().m_new_owner = item_new_owner;
+  }
 }
 
 template <int Dimension>
 std::vector<Array<const CellId>>
-ConnectivityDispatcher<Dimension>::_buildCellListToSend() const
+ConnectivityDispatcher<Dimension>::_buildCellListToSend()
 {
   const auto& node_to_cell_matrix
       = m_connectivity.nodeToCellMatrix();
   const auto& cell_to_node_matrix
       = m_connectivity.cellToNodeMatrix();
 
+  const auto& cell_new_owner = this->_dispatchedInfo<ItemType::cell>().m_new_owner;
+
   std::vector<std::vector<CellId>> cell_vector_to_send_by_proc(parallel::size());
   Array<bool> send_to_rank(parallel::size());
   for (CellId j=0; j<m_connectivity.numberOfCells(); ++j) {
@@ -88,7 +69,7 @@ ConnectivityDispatcher<Dimension>::_buildCellListToSend() const
       const auto& node_to_cell = node_to_cell_matrix[r];
       for (size_t K=0; K<node_to_cell.size(); ++K) {
         const CellId& k = node_to_cell[K];
-        send_to_rank[m_cell_new_owner[k]] = true;
+        send_to_rank[cell_new_owner[k]] = true;
       }
     }
 
@@ -111,16 +92,18 @@ ConnectivityDispatcher<Dimension>::_buildCellListToSend() const
 template <int Dimension>
 std::vector<Array<const NodeId>>
 ConnectivityDispatcher<Dimension>::
-_buildNodeListToSend() const
+_buildNodeListToSend()
 {
+  const auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
+
   const auto& cell_to_node_matrix = m_connectivity.cellToNodeMatrix();
   std::vector<Array<const NodeId>> node_list_to_send_by_proc(parallel::size());
   for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
     Array<bool> tag(m_connectivity.numberOfNodes());
     tag.fill(false);
     std::vector<NodeId> node_id_vector;
-    for (size_t j=0; j<m_cell_list_to_send_by_proc[i_rank].size(); ++j) {
-      const CellId& cell_id = m_cell_list_to_send_by_proc[i_rank][j];
+    for (size_t j=0; j<cell_list_to_send_by_proc[i_rank].size(); ++j) {
+      const CellId& cell_id = cell_list_to_send_by_proc[i_rank][j];
       const auto& cell_node_list = cell_to_node_matrix[cell_id];
       for (size_t r=0; r<cell_node_list.size(); ++r) {
         const NodeId& node_id = cell_node_list[r];
@@ -139,65 +122,202 @@ template <int Dimension>
 Array<const unsigned int>
 ConnectivityDispatcher<Dimension>::_buildNbCellToSend()
 {
+  const auto& item_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
   Array<unsigned int> nb_cell_to_send_by_proc(parallel::size());
   for (size_t i=0; i<parallel::size(); ++i) {
-    nb_cell_to_send_by_proc[i] = m_cell_list_to_send_by_proc[i].size();
+    nb_cell_to_send_by_proc[i] = item_list_to_send_by_proc[i].size();
   }
   return nb_cell_to_send_by_proc;
 }
 
 template <int Dimension>
+template <typename CellValueType,
+          typename DataType>
 void
-ConnectivityDispatcher<Dimension>::_dispatchFaces()
+ConnectivityDispatcher<Dimension>::_gatherFrom(const CellValueType& data_to_gather,
+                                               std::vector<DataType>& gathered_vector)
 {
-  if constexpr (Dimension>1) {
-    std::vector<Array<const int>> recv_number_of_face_per_cell_by_proc =
-        [&] () {
-          CellValue<int> number_of_face_per_cell(m_connectivity);
-          const auto& cell_to_face_matrix = m_connectivity.cellToFaceMatrix();
-          parallel_for(m_connectivity.numberOfCells(), PASTIS_LAMBDA(const CellId& j){
-              number_of_face_per_cell[j] = cell_to_face_matrix[j].size();
-            });
+  static_assert(std::is_same_v<std::remove_const_t<typename CellValueType::data_type>, DataType>);
 
-          return this->exchange(number_of_face_per_cell);
-        } ();
+  std::vector<Array<const DataType>> recv_cell_data_by_proc = this->exchange(data_to_gather);
 
-    std::vector<Array<int>> recv_cell_face_number_by_proc(parallel::size());
-    {
-      const auto& cell_to_face_matrix = m_connectivity.cellToFaceMatrix();
-      const FaceValue<const int>& face_number = m_connectivity.faceNumber();
+  auto& cell_number_id_map = this->_dispatchedInfo<ItemType::cell>().m_number_to_id_map;
+  gathered_vector.resize(cell_number_id_map.size());
+  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+    for (size_t i=0; i<m_recv_cell_number_by_proc[i_rank].size(); ++i) {
+      int cell_number = m_recv_cell_number_by_proc[i_rank][i];
+      const auto& searched_cell_id = cell_number_id_map.find(cell_number);
+      Assert(searched_cell_id != cell_number_id_map.end());
+      gathered_vector[searched_cell_id->second] = recv_cell_data_by_proc[i_rank][i];
+    }
+  }
+}
 
-      std::vector<Array<int>> cell_face_number_to_send_by_proc(parallel::size());
-      {
+template <int Dimension>
+std::unordered_map<int, int>
+ConnectivityDispatcher<Dimension>::_buildCellNumberIdMap()
+{
+  std::unordered_map<int, int> cell_number_id_map;
+  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+    int cpt=0;
+    for (size_t i=0; i<m_recv_cell_number_by_proc[i_rank].size(); ++i) {
+      int cell_number = m_recv_cell_number_by_proc[i_rank][i];
+      auto [iterator, inserted] = cell_number_id_map.insert(std::make_pair(cell_number, cpt));
+      if (inserted) cpt++;
+    }
+  }
+  return cell_number_id_map;
+}
+
+template <int Dimension>
+template <typename SubItemOfItemT>
+std::vector<Array<const int>>
+ConnectivityDispatcher<Dimension>::_getRecvNumberOfSubItemPerItemByProc()
+{
+  const auto& item_to_sub_item_matrix
+      = m_connectivity.template getItemToItemMatrix<SubItemOfItemT::item_type,
+                                                    SubItemOfItemT::sub_item_type>();
+
+  ItemValue<int, SubItemOfItemT::item_type> number_of_sub_item_per_item(m_connectivity);
+
+  using ItemId = ItemIdT<SubItemOfItemT::item_type>;
+  parallel_for(number_of_sub_item_per_item.size(), PASTIS_LAMBDA(const ItemId& j){
+      number_of_sub_item_per_item[j] = item_to_sub_item_matrix[j].size();
+    });
+  return this->exchange(number_of_sub_item_per_item);
+}
+
+template <int Dimension>
+template <typename SubItemOfItemT>
+std::vector<Array<const int>>
+ConnectivityDispatcher<Dimension>::
+_getRecvItemSubItemNumberingByProc(const std::vector<Array<const int>>& recv_number_of_sub_item_per_item_by_proc)
+{
+  std::vector<Array<const int>> item_sub_item_numbering_to_send_by_proc =
+      [&] () {
+        const auto& item_to_sub_item_matrix
+            = m_connectivity.template getItemToItemMatrix<SubItemOfItemT::item_type,
+                                                          SubItemOfItemT::sub_item_type>();
+
+        const ItemValue<const int, SubItemOfItemT::sub_item_type>& sub_item_number =
+            m_connectivity.template number<SubItemOfItemT::sub_item_type>();
+
+        using ItemId = ItemIdT<SubItemOfItemT::item_type>;
+        using SubItemId = ItemIdT<SubItemOfItemT::sub_item_type>;
+
+        std::vector<Array<const int>> item_sub_item_numbering_to_send_by_proc(parallel::size());
         for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-          std::vector<int> face_number_by_cell_vector;
-          for (size_t j=0; j<m_cell_list_to_send_by_proc[i_rank].size(); ++j) {
-            const CellId& cell_id = m_cell_list_to_send_by_proc[i_rank][j];
-            const auto& cell_face_list = cell_to_face_matrix[cell_id];
-            for (size_t r=0; r<cell_face_list.size(); ++r) {
-              const FaceId& face_id = cell_face_list[r];
-              face_number_by_cell_vector.push_back(face_number[face_id]);
+          const auto& item_list_to_send_by_proc
+              = this->_dispatchedInfo<SubItemOfItemT::item_type>().m_list_to_send_by_proc;
+
+          std::vector<int> sub_item_numbering_by_item_vector;
+          for (size_t j=0; j<item_list_to_send_by_proc[i_rank].size(); ++j) {
+            const ItemId& item_id = item_list_to_send_by_proc[i_rank][j];
+            const auto& sub_item_list = item_to_sub_item_matrix[item_id];
+            for (size_t r=0; r<sub_item_list.size(); ++r) {
+              const SubItemId& sub_item_id = sub_item_list[r];
+              sub_item_numbering_by_item_vector.push_back(sub_item_number[sub_item_id]);
             }
           }
-          cell_face_number_to_send_by_proc[i_rank] = convert_to_array(face_number_by_cell_vector);
+          item_sub_item_numbering_to_send_by_proc[i_rank] = convert_to_array(sub_item_numbering_by_item_vector);
         }
-      }
+        return item_sub_item_numbering_to_send_by_proc;
+      } ();
 
-      for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-        recv_cell_face_number_by_proc[i_rank]
-            = Array<int>(sum(recv_number_of_face_per_cell_by_proc[i_rank]));
-      }
+  std::vector<Array<int>> recv_item_sub_item_numbering_by_proc(parallel::size());
+  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
+    recv_item_sub_item_numbering_by_proc[i_rank]
+        = Array<int>(sum(recv_number_of_sub_item_per_item_by_proc[i_rank]));
+  }
+  parallel::exchange(item_sub_item_numbering_to_send_by_proc, recv_item_sub_item_numbering_by_proc);
+
+  std::vector<Array<const int>> const_recv_item_sub_item_numbering_by_proc(parallel::size());
+  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
+    const_recv_item_sub_item_numbering_by_proc[i_rank] = recv_item_sub_item_numbering_by_proc[i_rank];
+  }
+  return const_recv_item_sub_item_numbering_by_proc;
+}
 
-      parallel::exchange(cell_face_number_to_send_by_proc, recv_cell_face_number_by_proc);
+template <int Dimension>
+std::unordered_map<int, int>
+ConnectivityDispatcher<Dimension>::
+_buildNodeNumberIdMap(const std::vector<Array<const int>>& recv_cell_node_number_by_proc)
+{
+  std::unordered_map<int, int> node_number_id_map;
+  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+    int node_id=0;
+    for (size_t i=0; i<recv_cell_node_number_by_proc[i_rank].size(); ++i) {
+      int node_number = recv_cell_node_number_by_proc[i_rank][i];
+      auto [iterator, inserted] = node_number_id_map.insert(std::make_pair(node_number, node_id));
+      if (inserted) node_id++;
     }
+  }
+  return node_number_id_map;
+}
+
+
+template <int Dimension>
+template <ItemType item_type>
+void
+ConnectivityDispatcher<Dimension>::
+_buildRecvItemIdCorrespondanceByProc()
+{
+  const auto& item_list_to_send_by_proc = this->_dispatchedInfo<item_type>().m_list_to_send_by_proc;
+  using ItemId = ItemIdT<item_type>;
+
+  std::vector<Array<const ItemId>> recv_item_id_correspondance_by_proc(parallel::size());
+  const ItemValue<const int,item_type>& item_number =
+      m_connectivity.template number<item_type>();
+
+  std::vector<Array<const int>> send_item_number_by_proc(parallel::size());
+  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+    Array<int> send_item_number(item_list_to_send_by_proc[i_rank].size());
+    const Array<const ItemId> send_item_id = item_list_to_send_by_proc[i_rank];
+    parallel_for(send_item_number.size(), PASTIS_LAMBDA(const size_t& j){
+        send_item_number[j] = item_number[send_item_id[j]];
+      });
+    send_item_number_by_proc[i_rank] = send_item_number;
+  }
+
+  const auto& item_list_to_recv_size_by_proc = this->_dispatchedInfo<item_type>().m_list_to_recv_size_by_proc;
+  std::vector<Array<int>> recv_item_number_by_proc(parallel::size());
+  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
+    recv_item_number_by_proc[i_rank] = Array<int>(item_list_to_recv_size_by_proc[i_rank]);
+  }
+  parallel::exchange(send_item_number_by_proc, recv_item_number_by_proc);
+
+  const auto& item_number_to_id_map = this->_dispatchedInfo<item_type>().m_number_to_id_map;
+  for (size_t i_rank=0; i_rank<item_list_to_recv_size_by_proc.size(); ++i_rank) {
+    Array<ItemId> item_id_correspondance(item_list_to_recv_size_by_proc[i_rank]);
+    for (size_t l=0; l<item_list_to_recv_size_by_proc[i_rank]; ++l) {
+      const int& item_number = recv_item_number_by_proc[i_rank][l];
+      const auto& searched_item_id = item_number_to_id_map.find(item_number);
+      Assert(searched_item_id != item_number_to_id_map.end());
+      item_id_correspondance[l] = searched_item_id->second;
+    }
+    recv_item_id_correspondance_by_proc[i_rank] = item_id_correspondance;
+  }
+  this->_dispatchedInfo<item_type>().m_recv_id_correspondance_by_proc = recv_item_id_correspondance_by_proc;
+}
+
+template <int Dimension>
+void
+ConnectivityDispatcher<Dimension>::_dispatchFaces()
+{
+  if constexpr (Dimension>1) {
+    std::vector<Array<const int>> recv_number_of_face_per_cell_by_proc =
+        _getRecvNumberOfSubItemPerItemByProc<SubFaceOfCell>();
+
+    std::vector<Array<const int>> recv_cell_face_numbering_by_proc
+      = this->_getRecvItemSubItemNumberingByProc<SubFaceOfCell>(recv_number_of_face_per_cell_by_proc);
 
     const std::unordered_map<int, int> face_number_id_map
         = [&] () {
             std::unordered_map<int, int> face_number_id_map;
             for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
               int cpt=0;
-              for (size_t i=0; i<recv_cell_face_number_by_proc[i_rank].size(); ++i) {
-                int face_number = recv_cell_face_number_by_proc[i_rank][i];
+              for (size_t i=0; i<recv_cell_face_numbering_by_proc[i_rank].size(); ++i) {
+                int face_number = recv_cell_face_numbering_by_proc[i_rank][i];
                 auto [iterator, inserted] = face_number_id_map.insert(std::make_pair(face_number, cpt));
                 if (inserted) cpt++;
               }
@@ -211,27 +331,34 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
       m_new_descriptor.face_number_vector[id] = number;
     }
 
-    for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-      int l=0;
-      for (size_t i=0; i<m_nb_cell_to_recv_by_proc[i_rank]; ++i) {
-        std::vector<unsigned int> face_vector;
-        for (int k=0; k<recv_number_of_face_per_cell_by_proc[i_rank][i]; ++k) {
-          const auto& searched_face_id = face_number_id_map.find(recv_cell_face_number_by_proc[i_rank][l++]);
-          Assert(searched_face_id != face_number_id_map.end());
-          face_vector.push_back(searched_face_id->second);
+    {
+      const auto& cell_list_to_recv_size_by_proc =
+          this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
+
+      for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
+        int l=0;
+        for (size_t i=0; i<cell_list_to_recv_size_by_proc[i_rank]; ++i) {
+          std::vector<unsigned int> face_vector;
+          for (int k=0; k<recv_number_of_face_per_cell_by_proc[i_rank][i]; ++k) {
+            const auto& searched_face_id = face_number_id_map.find(recv_cell_face_numbering_by_proc[i_rank][l++]);
+            Assert(searched_face_id != face_number_id_map.end());
+            face_vector.push_back(searched_face_id->second);
+          }
+          m_new_descriptor.cell_to_face_vector.emplace_back(face_vector);
         }
-        m_new_descriptor.cell_to_face_vector.emplace_back(face_vector);
       }
     }
 
     {
       std::vector<Array<bool>> cell_face_is_reversed_to_send_by_proc(parallel::size());
       {
+        const auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
+
         const auto& cell_face_is_reversed = m_connectivity.cellFaceIsReversed();
         for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
           std::vector<bool> face_is_reversed_by_cell_vector;
-          for (size_t j=0; j<m_cell_list_to_send_by_proc[i_rank].size(); ++j) {
-            const CellId& cell_id = m_cell_list_to_send_by_proc[i_rank][j];
+          for (size_t j=0; j<cell_list_to_send_by_proc[i_rank].size(); ++j) {
+            const CellId& cell_id = cell_list_to_send_by_proc[i_rank][j];
             const auto& face_is_reversed = cell_face_is_reversed.itemValues(cell_id);
             for (size_t L=0; L<face_is_reversed.size(); ++L) {
               face_is_reversed_by_cell_vector.push_back(face_is_reversed[L]);
@@ -249,9 +376,12 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
       parallel::exchange(cell_face_is_reversed_to_send_by_proc, recv_cell_face_is_reversed_by_proc);
 
+      const auto& cell_list_to_recv_size_by_proc =
+          this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
+
       for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
         int l=0;
-        for (size_t i=0; i<m_nb_cell_to_recv_by_proc[i_rank]; ++i) {
+        for (size_t i=0; i<cell_list_to_recv_size_by_proc[i_rank]; ++i) {
           std::vector<bool> face_is_reversed_vector;
           for (int k=0; k<recv_number_of_face_per_cell_by_proc[i_rank][i]; ++k) {
             face_is_reversed_vector.push_back(recv_cell_face_is_reversed_by_proc[i_rank][l++]);
@@ -264,13 +394,14 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
     std::vector<Array<const FaceId>> send_face_id_by_proc(parallel::size());
     {
       const auto& cell_to_face_matrix = m_connectivity.cellToFaceMatrix();
+      const auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
 
       for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
         Array<bool> tag(m_connectivity.numberOfFaces());
         tag.fill(false);
         std::vector<FaceId> face_id_vector;
-        for (size_t j=0; j<m_cell_list_to_send_by_proc[i_rank].size(); ++j) {
-          const CellId& cell_id = m_cell_list_to_send_by_proc[i_rank][j];
+        for (size_t j=0; j<cell_list_to_send_by_proc[i_rank].size(); ++j) {
+          const CellId& cell_id = cell_list_to_send_by_proc[i_rank][j];
           const auto& cell_face_list = cell_to_face_matrix[cell_id];
           for (size_t l=0; l<cell_face_list.size(); ++l) {
             const FaceId& face_id = cell_face_list[l];
@@ -329,13 +460,14 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
 
     {
+      const auto& face_new_owner = this->_dispatchedInfo<ItemType::face>().m_new_owner;
       std::vector<Array<const int>> send_face_owner_by_proc(parallel::size());
       for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
         Array<int> send_face_owner(nb_face_to_send_by_proc[i_rank]);
         const Array<const FaceId> send_face_id = send_face_id_by_proc[i_rank];
         parallel_for(send_face_id.size(), PASTIS_LAMBDA(const size_t& l) {
             const FaceId& face_id = send_face_id[l];
-            send_face_owner[l] = m_face_new_owner[face_id];
+            send_face_owner[l] = face_new_owner[face_id];
           });
         send_face_owner_by_proc[i_rank] = send_face_owner;
       }
@@ -407,13 +539,14 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
       parallel::exchange(face_node_number_to_send_by_proc, recv_face_node_number_by_proc);
 
+      const auto& node_number_id_map = this->_dispatchedInfo<ItemType::node>().m_number_to_id_map;
       for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
         int l=0;
         for (size_t i=0; i<recv_face_number_by_proc[i_rank].size(); ++i) {
           std::vector<unsigned int> node_vector;
           for (int k=0; k<recv_face_number_of_node_by_proc[i_rank][i]; ++k) {
-            const auto& searched_node_id = m_node_number_id_map.find(recv_face_node_number_by_proc[i_rank][l++]);
-            Assert(searched_node_id != m_node_number_id_map.end());
+            const auto& searched_node_id = node_number_id_map.find(recv_face_node_number_by_proc[i_rank][l++]);
+            Assert(searched_node_id != node_number_id_map.end());
             node_vector.push_back(searched_node_id->second);
           }
           m_new_descriptor.face_to_node_vector.emplace_back(node_vector);
@@ -580,207 +713,81 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
 
 template <int Dimension>
-template <typename CellValueType,
-          typename DataType>
-void
-ConnectivityDispatcher<Dimension>::_gatherFrom(const CellValueType& data_to_gather,
-                                               std::vector<DataType>& gathered_vector)
-{
-  static_assert(std::is_same_v<std::remove_const_t<typename CellValueType::data_type>, DataType>);
-
-  std::vector<Array<const DataType>> recv_cell_data_by_proc = this->exchange(data_to_gather);
-
-  gathered_vector.resize(m_cell_number_id_map.size());
-  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-    for (size_t i=0; i<m_recv_cell_number_by_proc[i_rank].size(); ++i) {
-      int cell_number = m_recv_cell_number_by_proc[i_rank][i];
-      const auto& searched_cell_id = m_cell_number_id_map.find(cell_number);
-      Assert(searched_cell_id != m_cell_number_id_map.end());
-      gathered_vector[searched_cell_id->second] = recv_cell_data_by_proc[i_rank][i];
-    }
-  }
-}
-
-template <int Dimension>
-std::unordered_map<int, int>
-ConnectivityDispatcher<Dimension>::_buildCellNumberIdMap()
-{
-  std::unordered_map<int, int> cell_number_id_map;
-  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-    int cpt=0;
-    for (size_t i=0; i<m_recv_cell_number_by_proc[i_rank].size(); ++i) {
-      int cell_number = m_recv_cell_number_by_proc[i_rank][i];
-      auto [iterator, inserted] = cell_number_id_map.insert(std::make_pair(cell_number, cpt));
-      if (inserted) cpt++;
-    }
-  }
-  return cell_number_id_map;
-}
-
-template <int Dimension>
-std::vector<Array<const int>>
-ConnectivityDispatcher<Dimension>::_getRecvNumberOfNodePerCellByProc() const
-{
-  const auto& cell_to_node_matrix = m_connectivity.cellToNodeMatrix();
-  CellValue<int> number_of_node_per_cell(m_connectivity);
-  parallel_for(m_connectivity.numberOfCells(), PASTIS_LAMBDA(const CellId& j){
-      number_of_node_per_cell[j] = cell_to_node_matrix[j].size();
-    });
-  return this->exchange(number_of_node_per_cell);
-}
-
-template <int Dimension>
-std::vector<Array<const int>>
-ConnectivityDispatcher<Dimension>::
-_getRecvCellNodeNumberByProc(const std::vector<Array<const int>>& recv_number_of_node_per_cell_by_proc) const
-{
-  std::vector<Array<const int>> cell_node_number_to_send_by_proc =
-      [&] () {
-        const auto& cell_to_node_matrix = m_connectivity.cellToNodeMatrix();
-        const NodeValue<const int>& node_number = m_connectivity.nodeNumber();
-        std::vector<Array<const int>> cell_node_number_to_send_by_proc(parallel::size());
-        for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-          std::vector<int> node_number_by_cell_vector;
-          for (size_t j=0; j<m_cell_list_to_send_by_proc[i_rank].size(); ++j) {
-            const CellId& cell_id = m_cell_list_to_send_by_proc[i_rank][j];
-            const auto& cell_node_list = cell_to_node_matrix[cell_id];
-            for (size_t r=0; r<cell_node_list.size(); ++r) {
-              const NodeId& node_id = cell_node_list[r];
-              node_number_by_cell_vector.push_back(node_number[node_id]);
-            }
-          }
-          cell_node_number_to_send_by_proc[i_rank] = convert_to_array(node_number_by_cell_vector);
-        }
-        return cell_node_number_to_send_by_proc;
-      } ();
-
-  std::vector<Array<int>> recv_cell_node_number_by_proc(parallel::size());
-  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-    recv_cell_node_number_by_proc[i_rank]
-        = Array<int>(sum(recv_number_of_node_per_cell_by_proc[i_rank]));
-  }
-  parallel::exchange(cell_node_number_to_send_by_proc, recv_cell_node_number_by_proc);
-
-  std::vector<Array<const int>> const_recv_cell_node_number_by_proc(parallel::size());
-  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-    const_recv_cell_node_number_by_proc[i_rank] = recv_cell_node_number_by_proc[i_rank];
-  }
-  return const_recv_cell_node_number_by_proc;
-}
-
-template <int Dimension>
-std::unordered_map<int, int>
-ConnectivityDispatcher<Dimension>::
-_buildNodeNumberIdMap(const std::vector<Array<const int>>& recv_cell_node_number_by_proc)
+ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType& connectivity)
+    : m_connectivity(connectivity)
 {
-  std::unordered_map<int, int> node_number_id_map;
-  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-    int node_id=0;
-    for (size_t i=0; i<recv_cell_node_number_by_proc[i_rank].size(); ++i) {
-      int node_number = recv_cell_node_number_by_proc[i_rank][i];
-      auto [iterator, inserted] = node_number_id_map.insert(std::make_pair(node_number, node_id));
-      if (inserted) node_id++;
-    }
-  }
-  return node_number_id_map;
-}
+  this->_buildNewOwner<ItemType::cell>();
+  this->_buildNewOwner<ItemType::face>();
+  // this->_buildNewOwner<ItemType::edge>();
+  this->_buildNewOwner<ItemType::node>();
 
-template <int Dimension>
-std::vector<Array<const NodeId>>
-ConnectivityDispatcher<Dimension>::
-_buildRecvNodeIdCorrespondanceByProc() const
-{
-  std::vector<Array<const NodeId>> recv_node_id_correspondance_by_proc(parallel::size());
-  const NodeValue<const int>& node_number = m_connectivity.nodeNumber();
-  std::vector<Array<const int>> send_node_number_by_proc(parallel::size());
-  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-    Array<int> send_node_number(m_node_list_to_send_by_proc[i_rank].size());
-    const Array<const NodeId> send_node_id = m_node_list_to_send_by_proc[i_rank];
-    parallel_for(send_node_number.size(), PASTIS_LAMBDA(const size_t& j){
-        send_node_number[j] = node_number[send_node_id[j]];
-      });
-    send_node_number_by_proc[i_rank] = send_node_number;
-  }
+  m_dispatched_cell_info.m_list_to_send_by_proc = this->_buildCellListToSend();
+  this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc
+      = parallel::allToAll(this->_buildNbCellToSend());
 
-  std::vector<Array<int>> recv_node_number_by_proc(parallel::size());
-  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-    recv_node_number_by_proc[i_rank] = Array<int>(m_nb_node_to_recv_by_proc[i_rank]);
-  }
-  parallel::exchange(send_node_number_by_proc, recv_node_number_by_proc);
-
-  for (size_t i_rank=0; i_rank<m_nb_node_to_recv_by_proc.size(); ++i_rank) {
-    Array<NodeId> node_id_correspondace(m_nb_node_to_recv_by_proc[i_rank]);
-    for (size_t l=0; l<m_nb_node_to_recv_by_proc[i_rank]; ++l) {
-      const int& node_number = recv_node_number_by_proc[i_rank][l];
-      const auto& searched_node_id = m_node_number_id_map.find(node_number);
-      Assert(searched_node_id != m_node_number_id_map.end());
-      node_id_correspondace[l] = searched_node_id->second;
-    }
-    recv_node_id_correspondance_by_proc[i_rank] = node_id_correspondace;
-  }
-  return recv_node_id_correspondance_by_proc;
-}
+  m_recv_cell_number_by_proc = this->exchange(m_connectivity.cellNumber());
+  this->_dispatchedInfo<ItemType::cell>().m_number_to_id_map
+      = this->_buildCellNumberIdMap();
 
-template <int Dimension>
-ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType& connectivity)
-    : m_connectivity(connectivity),
-      m_cell_new_owner(this->_getCellNewOwner()),
-      m_face_new_owner(this->_getFaceNewOwner()),
-      m_node_new_owner(this->_getNodeNewOwner()),
-      m_cell_list_to_send_by_proc(this->_buildCellListToSend()),
-      m_nb_cell_to_recv_by_proc(parallel::allToAll(this->_buildNbCellToSend())),
-      m_recv_cell_number_by_proc(this->exchange(m_connectivity.cellNumber())),
-      m_cell_number_id_map(this->_buildCellNumberIdMap())
-{
   const std::vector<Array<const int>> recv_number_of_node_per_cell_by_proc
-      = this->_getRecvNumberOfNodePerCellByProc();
+      = this->_getRecvNumberOfSubItemPerItemByProc<SubNodeOfCell>();
 
-  const std::vector<Array<const int>> recv_cell_node_number_by_proc =
-      this->_getRecvCellNodeNumberByProc(recv_number_of_node_per_cell_by_proc);
+  const std::vector<Array<const int>> recv_cell_node_numbering_by_proc
+      = this->_getRecvItemSubItemNumberingByProc<SubNodeOfCell>(recv_number_of_node_per_cell_by_proc);
 
-  this->_buildNodeNumberIdMap(recv_cell_node_number_by_proc);
-  m_node_number_id_map = _buildNodeNumberIdMap(recv_cell_node_number_by_proc);
+  this->_buildNodeNumberIdMap(recv_cell_node_numbering_by_proc);
+  this->_dispatchedInfo<ItemType::node>().m_number_to_id_map
+      = this->_buildNodeNumberIdMap(recv_cell_node_numbering_by_proc);
 
-  m_new_descriptor.cell_number_vector.resize(m_cell_number_id_map.size());
-  for (const auto& [number, id] : m_cell_number_id_map) {
-    m_new_descriptor.cell_number_vector[id] = number;
+  {
+    const auto& cell_number_id_map  = this->_dispatchedInfo<ItemType::cell>().m_number_to_id_map;
+    m_new_descriptor.cell_number_vector.resize(cell_number_id_map.size());
+    for (const auto& [number, id] : cell_number_id_map) {
+      m_new_descriptor.cell_number_vector[id] = number;
+    }
   }
 
-  m_node_list_to_send_by_proc = this->_buildNodeListToSend();
+  m_dispatched_node_info.m_list_to_send_by_proc = this->_buildNodeListToSend();
 
   Array<unsigned int> nb_node_to_send_by_proc(parallel::size());
   for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-    nb_node_to_send_by_proc[i_rank] = m_node_list_to_send_by_proc[i_rank].size();
+    nb_node_to_send_by_proc[i_rank] = m_dispatched_node_info.m_list_to_send_by_proc[i_rank].size();
   }
-  m_nb_node_to_recv_by_proc = parallel::allToAll(nb_node_to_send_by_proc);
+  this->_dispatchedInfo<ItemType::node>().m_list_to_recv_size_by_proc
+      = parallel::allToAll(nb_node_to_send_by_proc);
 
-  m_recv_node_id_correspondance_by_proc = this->_buildRecvNodeIdCorrespondanceByProc();
+  this->_buildRecvItemIdCorrespondanceByProc<ItemType::node>();
 
   // Fill new descriptor
   this->_gatherFrom(m_connectivity.cellType(), m_new_descriptor.cell_type_vector);
-  this->_gatherFrom(m_cell_new_owner, m_new_descriptor.cell_owner_vector);
+  this->_gatherFrom(this->_dispatchedInfo<ItemType::cell>().m_new_owner, m_new_descriptor.cell_owner_vector);
 
-  m_new_descriptor.node_number_vector.resize(m_node_number_id_map.size());
-  for (const auto& [number, id] : m_node_number_id_map) {
-    m_new_descriptor.node_number_vector[id] = number;
+  {
+    const auto& node_number_id_map = this->_dispatchedInfo<ItemType::node>().m_number_to_id_map;
+    m_new_descriptor.node_number_vector.resize(node_number_id_map.size());
+    for (const auto& [number, id] : node_number_id_map) {
+      m_new_descriptor.node_number_vector[id] = number;
+    }
   }
 
   {
+    const auto& node_new_owner = this->_dispatchedInfo<ItemType::node>().m_new_owner;
     std::vector<Array<const int>> send_node_owner_by_proc(parallel::size());
     for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
       Array<int> send_node_owner(nb_node_to_send_by_proc[i_rank]);
-      const Array<const NodeId> send_node_id = m_node_list_to_send_by_proc[i_rank];
+      const Array<const NodeId> send_node_id = m_dispatched_node_info.m_list_to_send_by_proc[i_rank];
       parallel_for(send_node_id.size(), PASTIS_LAMBDA(const size_t& r) {
           const NodeId& node_id = send_node_id[r];
-          send_node_owner[r] = m_node_new_owner[node_id];
+          send_node_owner[r] = node_new_owner[node_id];
         });
       send_node_owner_by_proc[i_rank] = send_node_owner;
     }
 
+    const auto& node_list_to_recv_size_by_proc = this->_dispatchedInfo<ItemType::node>().m_list_to_recv_size_by_proc;
 #warning use a _gatherFrom-like function
     std::vector<Array<int>> recv_node_owner_by_proc(parallel::size());
     for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-      recv_node_owner_by_proc[i_rank] = Array<int>(m_nb_node_to_recv_by_proc[i_rank]);
+      recv_node_owner_by_proc[i_rank] = Array<int>(node_list_to_recv_size_by_proc[i_rank]);
     }
     parallel::exchange(send_node_owner_by_proc, recv_node_owner_by_proc);
 
@@ -793,20 +800,24 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
     }
   }
 
-  for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-    int l=0;
-    for (size_t i=0; i<m_nb_cell_to_recv_by_proc[i_rank]; ++i) {
-      std::vector<unsigned int> node_vector;
-      for (int k=0; k<recv_number_of_node_per_cell_by_proc[i_rank][i]; ++k) {
-        const auto& searched_node_id = m_node_number_id_map.find(recv_cell_node_number_by_proc[i_rank][l++]);
-        Assert(searched_node_id != m_node_number_id_map.end());
-        node_vector.push_back(searched_node_id->second);
+  {
+    const auto& cell_list_to_recv_size_by_proc =
+        this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
+
+    const auto& node_number_id_map  = this->_dispatchedInfo<ItemType::node>().m_number_to_id_map;
+    for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
+      int l=0;
+      for (size_t i=0; i<cell_list_to_recv_size_by_proc[i_rank]; ++i) {
+        std::vector<unsigned int> node_vector;
+        for (int k=0; k<recv_number_of_node_per_cell_by_proc[i_rank][i]; ++k) {
+          const auto& searched_node_id = node_number_id_map.find(recv_cell_node_numbering_by_proc[i_rank][l++]);
+          Assert(searched_node_id != node_number_id_map.end());
+          node_vector.push_back(searched_node_id->second);
+        }
+        m_new_descriptor.cell_by_node_vector.emplace_back(node_vector);
       }
-      m_new_descriptor.cell_by_node_vector.emplace_back(node_vector);
     }
   }
-
-
   this->_dispatchFaces();
 
   m_dispatched_connectivity = ConnectivityType::build(m_new_descriptor);
diff --git a/src/mesh/ConnectivityDispatcher.hpp b/src/mesh/ConnectivityDispatcher.hpp
index 00d10bdad..c68e3f857 100644
--- a/src/mesh/ConnectivityDispatcher.hpp
+++ b/src/mesh/ConnectivityDispatcher.hpp
@@ -15,41 +15,70 @@ class ConnectivityDispatcher
 
  private:
   const ConnectivityType& m_connectivity;
-
   ConnectivityDescriptor m_new_descriptor;
-
   std::shared_ptr<ConnectivityType> m_dispatched_connectivity;
 
-  const CellValue<const int> m_cell_new_owner;
-  const FaceValue<const int> m_face_new_owner;
-  const NodeValue<const int> m_node_new_owner;
-
-  const std::vector<Array<const CellId>> m_cell_list_to_send_by_proc;
-#warning use a const sementic too
-  std::vector<Array<const NodeId>> m_node_list_to_send_by_proc;
-
-  const Array<const unsigned int> m_nb_cell_to_recv_by_proc;
-  const std::vector<Array<const int>> m_recv_cell_number_by_proc;
-  const std::unordered_map<int, int> m_cell_number_id_map;
-
-  Array<const unsigned int> m_nb_node_to_recv_by_proc;
+  template <ItemType item_type>
+  struct DispatchedItemInfo
+  {
+    using ItemId = ItemIdT<item_type>;
+    ItemValue<const int, item_type> m_new_owner;
+    std::vector<Array<const ItemId>> m_list_to_send_by_proc;
+#warning is m_list_to_recv_size_by_proc really necessary?
+    Array<const unsigned int> m_list_to_recv_size_by_proc;
+    std::unordered_map<int, int> m_number_to_id_map;
+    std::vector<Array<const ItemId>> m_recv_id_correspondance_by_proc;
+  };
+
+  DispatchedItemInfo<ItemType::cell> m_dispatched_cell_info;
+  DispatchedItemInfo<ItemType::face> m_dispatched_face_info;
+  DispatchedItemInfo<ItemType::edge> m_dispatched_edge_info;
+  DispatchedItemInfo<ItemType::node> m_dispatched_node_info;
+
+  template <ItemType item_type>
+  PASTIS_INLINE
+  DispatchedItemInfo<item_type>& _dispatchedInfo()
+  {
+    if constexpr (item_type == ItemType::cell) {
+      return m_dispatched_cell_info;
+    } else if constexpr (item_type == ItemType::face) {
+      return m_dispatched_face_info;
+    } else if constexpr (item_type == ItemType::edge) {
+      return m_dispatched_edge_info;
+    } else {
+      return m_dispatched_node_info;
+    }
+  }
 
-  std::unordered_map<int, int> m_node_number_id_map;
+  template <ItemType item_type>
+  PASTIS_INLINE
+  const DispatchedItemInfo<item_type>& _dispatchedInfo() const
+  {
+    if constexpr (item_type == ItemType::cell) {
+      return m_dispatched_cell_info;
+    } else if constexpr (item_type == ItemType::face) {
+      return m_dispatched_face_info;
+    } else if constexpr (item_type == ItemType::edge) {
+      return m_dispatched_edge_info;
+    } else {
+      return m_dispatched_node_info;
+    }
+  }
 
-  std::vector<Array<const NodeId>> m_recv_node_id_correspondance_by_proc;
+  std::vector<Array<const int>> m_recv_cell_number_by_proc;
+  std::vector<Array<const NodeId>>& m_recv_node_id_correspondance_by_proc =
+      m_dispatched_node_info.m_recv_id_correspondance_by_proc;
 
-  CellValue<int> _getCellNewOwner();
-  FaceValue<int> _getFaceNewOwner();
-  NodeValue<int> _getNodeNewOwner();
+  template <ItemType item_type>
+  void _buildNewOwner();
 
-  std::vector<Array<const CellId>> _buildCellListToSend() const;
+  std::vector<Array<const CellId>> _buildCellListToSend();
 
-  std::vector<Array<const NodeId>> _buildNodeListToSend() const;
+  std::vector<Array<const NodeId>> _buildNodeListToSend();
 
   Array<const unsigned int> _buildNbCellToSend();
 
-  std::unordered_map<int, int>
-  _buildCellNumberIdMap();
+  std::unordered_map<int, int> _buildCellNumberIdMap();
 
   std::unordered_map<int, int>
   _buildNodeNumberIdMap(const std::vector<Array<const int>>& recv_cell_node_number_by_proc);
@@ -61,14 +90,16 @@ class ConnectivityDispatcher
   void _gatherFrom(const CellValueType& data_to_gather,
                    std::vector<DataType>& gathered_vector);
 
+  template <typename SubItemOfItemT>
   std::vector<Array<const int>>
-  _getRecvNumberOfNodePerCellByProc() const;
+  _getRecvNumberOfSubItemPerItemByProc();
 
+  template <typename SubItemOfItemT>
   std::vector<Array<const int>>
-  _getRecvCellNodeNumberByProc(const std::vector<Array<const int>>& recv_number_of_node_per_cell_by_proc) const;
+  _getRecvItemSubItemNumberingByProc(const std::vector<Array<const int>>& recv_number_of_sub_item_per_item_by_proc);
 
-  std::vector<Array<const NodeId>>
-  _buildRecvNodeIdCorrespondanceByProc() const;
+  template <ItemType item_type>
+  void _buildRecvItemIdCorrespondanceByProc();
 
  public:
   std::shared_ptr<const ConnectivityType>
@@ -77,32 +108,17 @@ class ConnectivityDispatcher
     return m_dispatched_connectivity;
   }
 
-  PASTIS_INLINE
-  const CellValue<const int>& cellNewOwner() const
-  {
-    return m_cell_new_owner;
-  }
-
-  PASTIS_INLINE
-  const FaceValue<const int>& faceNewOwner() const
-  {
-    return m_face_new_owner;
-  }
-
-  PASTIS_INLINE
-  const NodeValue<const int>& nodeNewOwner() const
-  {
-    return m_node_new_owner;
-  }
-
   template<typename DataType, typename ConnectivityPtr>
   std::vector<Array<const DataType>>
   exchange(ItemValue<DataType, ItemType::cell, ConnectivityPtr> cell_value) const
   {
     using MutableDataType = std::remove_const_t<DataType>;
     std::vector<Array<const DataType>> cell_value_to_send_by_proc(parallel::size());
+
+    const auto& item_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
+
     for (size_t i=0; i<parallel::size(); ++i) {
-      const Array<const CellId>& cell_list = m_cell_list_to_send_by_proc[i];
+      const Array<const CellId>& cell_list = item_list_to_send_by_proc[i];
       Array<MutableDataType> cell_value_list(cell_list.size());
       parallel_for (cell_list.size(), PASTIS_LAMBDA(const CellId& cell_id) {
           cell_value_list[cell_id] = cell_value[cell_list[cell_id]];
@@ -111,10 +127,12 @@ class ConnectivityDispatcher
     }
 
     std::vector<Array<MutableDataType>> recv_cell_value_by_proc(parallel::size());
-    for (size_t i=0; i<parallel::size(); ++i) {
-      recv_cell_value_by_proc[i] = Array<MutableDataType>(m_nb_cell_to_recv_by_proc[i]);
+    {
+      const auto& list_to_recv_size_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
+      for (size_t i=0; i<parallel::size(); ++i) {
+        recv_cell_value_by_proc[i] = Array<MutableDataType>(list_to_recv_size_by_proc[i]);
+      }
     }
-
     parallel::exchange(cell_value_to_send_by_proc, recv_cell_value_by_proc);
 
     std::vector<Array<const DataType>> const_recv_cell_value_by_proc(parallel::size());
@@ -125,39 +143,48 @@ class ConnectivityDispatcher
     return const_recv_cell_value_by_proc;
   }
 
-#warning Should write this function generically w.r. to the item type
-  template<typename DataType, typename ConnectivityPtr>
-  ItemValue<std::remove_const_t<DataType>, ItemType::node, ConnectivityPtr>
-  dispatch(ItemValue<DataType, ItemType::node, ConnectivityPtr> node_value) const
+  template<typename DataType, ItemType item_type, typename ConnectivityPtr>
+  ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr>
+  dispatch(ItemValue<DataType, item_type, ConnectivityPtr> item_value) const
   {
+    using ItemId = ItemIdT<item_type>;
+
     Assert(m_dispatched_connectivity.use_count()> 0,
            "cannot dispatch quantity before connectivity");
+
+    const auto& item_list_to_send_by_proc = this->_dispatchedInfo<item_type>().m_list_to_send_by_proc;
+
     using MutableDataType = std::remove_const_t<DataType>;
-    std::vector<Array<DataType>> node_value_to_send_by_proc(parallel::size());
+    std::vector<Array<DataType>> item_value_to_send_by_proc(parallel::size());
     for (size_t i=0; i<parallel::size(); ++i) {
-      const Array<const NodeId>& node_list = m_node_list_to_send_by_proc[i];
-      Array<MutableDataType> node_value_list(node_list.size());
-      parallel_for (node_list.size(), PASTIS_LAMBDA(const NodeId& node_id) {
-          node_value_list[node_id] = node_value[node_list[node_id]];
+      const Array<const ItemId>& item_list = item_list_to_send_by_proc[i];
+      Array<MutableDataType> item_value_list(item_list.size());
+      parallel_for (item_list.size(), PASTIS_LAMBDA(const ItemId& item_id) {
+          item_value_list[item_id] = item_value[item_list[item_id]];
         });
-      node_value_to_send_by_proc[i] = node_value_list;
+      item_value_to_send_by_proc[i] = item_value_list;
     }
 
-    std::vector<Array<MutableDataType>> recv_node_value_by_proc(parallel::size());
+    const auto& item_list_to_recv_size_by_proc = this->_dispatchedInfo<item_type>().m_list_to_recv_size_by_proc;
+    std::vector<Array<MutableDataType>> recv_item_value_by_proc(parallel::size());
     for (size_t i=0; i<parallel::size(); ++i) {
-      recv_node_value_by_proc[i] = Array<MutableDataType>(m_nb_node_to_recv_by_proc[i]);
+      recv_item_value_by_proc[i] = Array<MutableDataType>(item_list_to_recv_size_by_proc[i]);
     }
 
-    parallel::exchange(node_value_to_send_by_proc, recv_node_value_by_proc);
+    parallel::exchange(item_value_to_send_by_proc, recv_item_value_by_proc);
 
-    NodeValue<MutableDataType> new_node_value(*m_dispatched_connectivity);
+    const auto& recv_item_id_correspondance_by_proc =
+        this->_dispatchedInfo<item_type>().m_recv_id_correspondance_by_proc;
+    ItemValue<MutableDataType, item_type> new_item_value(*m_dispatched_connectivity);
     for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-      for (size_t r=0; r<recv_node_value_by_proc[i_rank].size(); ++r) {
-        const NodeId& node_id = m_recv_node_id_correspondance_by_proc[i_rank][r];
-        new_node_value[node_id] = recv_node_value_by_proc[i_rank][r];
-      }
+      const auto& recv_item_id_correspondance = recv_item_id_correspondance_by_proc[i_rank];
+      const auto& recv_item_value = recv_item_value_by_proc[i_rank];
+      parallel_for(recv_item_value.size(), PASTIS_LAMBDA(size_t r) {
+          const ItemId& item_id = recv_item_id_correspondance[r];
+          new_item_value[item_id] = recv_item_value[r];
+        });
     }
-    return new_node_value;
+    return new_item_value;
   }
 
   ConnectivityDispatcher(const ConnectivityType& mesh);
diff --git a/src/mesh/SubItemOfItemType.hpp b/src/mesh/SubItemOfItemType.hpp
new file mode 100644
index 000000000..dbf382559
--- /dev/null
+++ b/src/mesh/SubItemOfItemType.hpp
@@ -0,0 +1,32 @@
+#ifndef SUB_ITEM_OF_ITEM_TYPE_HPP
+#define SUB_ITEM_OF_ITEM_TYPE_HPP
+
+#include <ItemType.hpp>
+
+template <ItemType sub_item_t,
+          ItemType item_t>
+struct SubItemOfItemType
+{
+  static_assert(sub_item_t != item_t, "item and its sub-item cannot be of same type");
+
+  constexpr static ItemType sub_item_type = sub_item_t;
+  constexpr static ItemType item_type = item_t;
+};
+
+using SubFaceOfCell = SubItemOfItemType<ItemType::face, ItemType::cell>;
+using SubEdgeOfCell = SubItemOfItemType<ItemType::edge, ItemType::cell>;
+using SubNodeOfCell = SubItemOfItemType<ItemType::node, ItemType::cell>;
+
+using SubCellofFace = SubItemOfItemType<ItemType::cell, ItemType::face>;
+using SubEdgeOfFace = SubItemOfItemType<ItemType::edge, ItemType::face>;
+using SubNodeOfFace = SubItemOfItemType<ItemType::node, ItemType::face>;
+
+using SubCellofEdge = SubItemOfItemType<ItemType::cell, ItemType::edge>;
+using SubFaceOfEdge = SubItemOfItemType<ItemType::face, ItemType::edge>;
+using SubNodeOfEdge = SubItemOfItemType<ItemType::node, ItemType::edge>;
+
+using SubCellofNode = SubItemOfItemType<ItemType::cell, ItemType::node>;
+using SubFaceOfNode = SubItemOfItemType<ItemType::face, ItemType::node>;
+using SubEdgeOfNode = SubItemOfItemType<ItemType::edge, ItemType::node>;
+
+#endif // SUB_ITEM_OF_ITEM_TYPE_HPP
-- 
GitLab