diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp
index f88f596f1d9776cbc628d012e3675e1d23584612..d7fd7370785b7addef61ceeead352bcfeb9cf922 100644
--- a/src/mesh/ConnectivityDispatcher.cpp
+++ b/src/mesh/ConnectivityDispatcher.cpp
@@ -48,74 +48,72 @@ ConnectivityDispatcher<Dimension>::_buildNewOwner()
 }
 
 template <int Dimension>
-std::vector<Array<const CellId>>
-ConnectivityDispatcher<Dimension>::_buildCellListToSend()
+template <ItemType item_type>
+void
+ConnectivityDispatcher<Dimension>::_buildItemListToSend()
 {
-  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) {
-    send_to_rank.fill(false);
-    const auto& cell_to_node = cell_to_node_matrix[j];
-
-    for (size_t R=0; R<cell_to_node.size(); ++R) {
-      const NodeId& r = cell_to_node[R];
-      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[cell_new_owner[k]] = true;
+  if constexpr (item_type == ItemType::cell) {
+    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) {
+      send_to_rank.fill(false);
+      const auto& cell_to_node = cell_to_node_matrix[j];
+
+      for (size_t R=0; R<cell_to_node.size(); ++R) {
+        const NodeId& r = cell_to_node[R];
+        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[cell_new_owner[k]] = true;
+        }
       }
-    }
 
-    for (size_t k=0; k<send_to_rank.size(); ++k) {
-      if (send_to_rank[k]) {
-        cell_vector_to_send_by_proc[k].push_back(j);
+      for (size_t k=0; k<send_to_rank.size(); ++k) {
+        if (send_to_rank[k]) {
+          cell_vector_to_send_by_proc[k].push_back(j);
+        }
       }
     }
-  }
-
-  std::vector<Array<const CellId>> cell_list_to_send_by_proc(parallel::size());
-  for (size_t i=0; i<parallel::size(); ++i) {
-    cell_list_to_send_by_proc[i] = convert_to_array(cell_vector_to_send_by_proc[i]);
-  }
 
-  return cell_list_to_send_by_proc;
-}
+    auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
+    cell_list_to_send_by_proc.resize(parallel::size());
+    for (size_t i=0; i<parallel::size(); ++i) {
+      cell_list_to_send_by_proc[i] = convert_to_array(cell_vector_to_send_by_proc[i]);
+    }
+  } else {
+    const auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
 
+    using ItemId = ItemIdT<item_type>;
+    const auto& cell_to_sub_item_matrix = m_connectivity.template getItemToItemMatrix<ItemType::cell,item_type>();
 
-template <int Dimension>
-std::vector<Array<const NodeId>>
-ConnectivityDispatcher<Dimension>::
-_buildNodeListToSend()
-{
-  const auto& cell_list_to_send_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_send_by_proc;
+    auto& item_list_to_send_by_proc = this->_dispatchedInfo<item_type>().m_list_to_send_by_proc;
+    item_list_to_send_by_proc.resize(parallel::size());
 
-  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<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];
-        if (not tag[node_id]) {
-          node_id_vector.push_back(node_id);
-          tag[node_id] = true;
+    for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+      Array<bool> tag(m_connectivity.template numberOf<item_type>());
+      tag.fill(false);
+      std::vector<ItemId> item_id_vector;
+      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_sub_item_list = cell_to_sub_item_matrix[cell_id];
+        for (size_t r=0; r<cell_sub_item_list.size(); ++r) {
+          const ItemId& item_id = cell_sub_item_list[r];
+          if (not tag[item_id]) {
+            item_id_vector.push_back(item_id);
+            tag[item_id] = true;
+          }
         }
       }
+      item_list_to_send_by_proc[i_rank] = convert_to_array(item_id_vector);
     }
-    node_list_to_send_by_proc[i_rank] = convert_to_array(node_id_vector);
   }
-  return node_list_to_send_by_proc;
 }
 
 template <int Dimension>
@@ -131,42 +129,61 @@ ConnectivityDispatcher<Dimension>::_buildNbCellToSend()
 }
 
 template <int Dimension>
-template <typename CellValueType,
-          typename DataType>
+template<typename DataType, ItemType item_type, typename ConnectivityPtr>
 void
-ConnectivityDispatcher<Dimension>::_gatherFrom(const CellValueType& data_to_gather,
-                                               std::vector<DataType>& gathered_vector)
+ConnectivityDispatcher<Dimension>::
+_gatherFrom(const ItemValue<DataType, item_type, ConnectivityPtr>& data_to_gather,
+            std::vector<std::remove_const_t<DataType>>& gathered_vector)
 {
-  static_assert(std::is_same_v<std::remove_const_t<typename CellValueType::data_type>, DataType>);
+  std::vector<Array<const DataType>> recv_item_data_by_proc = this->exchange(data_to_gather);
 
-  std::vector<Array<const DataType>> recv_cell_data_by_proc = this->exchange(data_to_gather);
+  const auto& recv_id_correspondance_by_proc = this->_dispatchedInfo<item_type>().m_recv_id_correspondance_by_proc;
+  Assert(recv_id_correspondance_by_proc.size()==parallel::size());
 
+  gathered_vector.resize(this->_dispatchedInfo<item_type>().m_number_to_id_map.size());
+  for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+    Assert(recv_id_correspondance_by_proc[i_rank].size()==recv_item_data_by_proc[i_rank].size());
+    for (size_t r=0; r<recv_id_correspondance_by_proc[i_rank].size(); ++r) {
+      const auto& item_id = recv_id_correspondance_by_proc[i_rank][r];
+      gathered_vector[item_id] = recv_item_data_by_proc[i_rank][r];
+    }
+  }
+}
+
+template <int Dimension>
+void
+ConnectivityDispatcher<Dimension>::
+_buildCellNumberIdMap()
+{
+  const auto recv_cell_number_by_proc = this->exchange(m_connectivity.template number<ItemType::cell>());
   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];
+    CellId cell_id=0;
+    for (size_t i=0; i<recv_cell_number_by_proc[i_rank].size(); ++i) {
+      const int cell_number = recv_cell_number_by_proc[i_rank][i];
+      auto [iterator, inserted] = cell_number_id_map.insert(std::make_pair(cell_number, cell_id));
+      if (inserted) ++cell_id;
     }
   }
 }
 
 template <int Dimension>
-std::unordered_map<int, int>
-ConnectivityDispatcher<Dimension>::_buildCellNumberIdMap()
+template <typename SubItemOfItemT>
+void
+ConnectivityDispatcher<Dimension>::
+_buildSubItemNumberIdMapAs(const std::vector<Array<const int>>& recv_cell_sub_item_number_by_proc)
 {
-  std::unordered_map<int, int> cell_number_id_map;
+  static_assert(SubItemOfItemT::item_type == ItemType::cell, "Dispatcher requires to be build using cell as master entities");
+
+  auto& sub_item_number_id_map = this->_dispatchedInfo<SubItemOfItemT::sub_item_type>().m_number_to_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++;
+    int sub_item_id=0;
+    for (size_t i=0; i<recv_cell_sub_item_number_by_proc[i_rank].size(); ++i) {
+      int node_number = recv_cell_sub_item_number_by_proc[i_rank][i];
+      auto [iterator, inserted] = sub_item_number_id_map.insert(std::make_pair(node_number, sub_item_id));
+      if (inserted) sub_item_id++;
     }
   }
-  return cell_number_id_map;
 }
 
 template <int Dimension>
@@ -238,24 +255,6 @@ _getRecvItemSubItemNumberingByProc(const std::vector<Array<const int>>& recv_num
   return const_recv_item_sub_item_numbering_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
@@ -311,25 +310,24 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
     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_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++;
-              }
-            }
-            return face_number_id_map;
-          } ();
+    this->_buildSubItemNumberIdMapAs<SubFaceOfCell>(recv_cell_face_numbering_by_proc);
+
+    const std::unordered_map<int, int>& face_number_id_map =
+        this->_dispatchedInfo<ItemType::face>().m_number_to_id_map;
 
+    this->_buildItemListToSend<ItemType::face>();
 
-    m_new_descriptor.face_number_vector.resize(face_number_id_map.size());
-    for (const auto& [number, id] : face_number_id_map) {
-      m_new_descriptor.face_number_vector[id] = number;
+#warning this patterns repeats for each item type. Should be factorized
+    Array<unsigned int> nb_face_to_send_by_proc(parallel::size());
+    for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
+      nb_face_to_send_by_proc[i_rank] = m_dispatched_face_info.m_list_to_send_by_proc[i_rank].size();
     }
+    this->_dispatchedInfo<ItemType::face>().m_list_to_recv_size_by_proc
+        = parallel::allToAll(nb_face_to_send_by_proc);
+
+    this->_buildRecvItemIdCorrespondanceByProc<ItemType::face>();
+    this->_gatherFrom(m_connectivity.template number<ItemType::face>(), m_new_descriptor.face_number_vector);
+
 
     {
       const auto& cell_list_to_recv_size_by_proc =
@@ -391,161 +389,22 @@ 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<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];
-            if (not tag[face_id]) {
-              face_id_vector.push_back(face_id);
-              tag[face_id] = true;
-            }
-          }
-        }
-        send_face_id_by_proc[i_rank] = convert_to_array(face_id_vector);
-      }
-    }
+    this->_gatherFrom(this->_dispatchedInfo<ItemType::face>().m_new_owner, m_new_descriptor.face_owner_vector);
 
-    std::vector<Array<const int>> send_face_number_by_proc(parallel::size());
-    {
-      const FaceValue<const int>& face_number = m_connectivity.faceNumber();
-
-      for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-        Array<int> send_face_number(send_face_id_by_proc[i_rank].size());
-        const Array<const FaceId> send_face_id = send_face_id_by_proc[i_rank];
-        parallel_for(send_face_number.size(), PASTIS_LAMBDA(const size_t& j){
-            send_face_number[j] = face_number[send_face_id[j]];
-          });
-        send_face_number_by_proc[i_rank] = send_face_number;
-      }
-    }
-
-    Array<unsigned int> nb_face_to_send_by_proc(parallel::size());
-    for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-      nb_face_to_send_by_proc[i_rank] = send_face_id_by_proc[i_rank].size();
-    }
-    Array<const unsigned int> nb_face_to_recv_by_proc
-        = parallel::allToAll(nb_face_to_send_by_proc);
-
-    std::vector<Array<int>> recv_face_number_by_proc(parallel::size());
-    {
-      for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-        recv_face_number_by_proc[i_rank] = Array<int>(nb_face_to_recv_by_proc[i_rank]);
-      }
-      parallel::exchange(send_face_number_by_proc, recv_face_number_by_proc);
-    }
-
-    std::vector<Array<const FaceId>> recv_face_id_correspondance_by_proc(parallel::size());
-    {
-      for (size_t i_rank=0; i_rank<nb_face_to_recv_by_proc.size(); ++i_rank) {
-        Array<FaceId> face_id_correspondace(nb_face_to_recv_by_proc[i_rank]);
-        for (size_t l=0; l<nb_face_to_recv_by_proc[i_rank]; ++l) {
-          const int& face_number = recv_face_number_by_proc[i_rank][l];
-          const auto& searched_face_id = face_number_id_map.find(face_number);
-          Assert(searched_face_id != face_number_id_map.end());
-          face_id_correspondace[l] = searched_face_id->second;
-        }
-        recv_face_id_correspondance_by_proc[i_rank] = face_id_correspondace;
-      }
-    }
-
-
-    {
-      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] = face_new_owner[face_id];
-          });
-        send_face_owner_by_proc[i_rank] = send_face_owner;
-      }
-
-      std::vector<Array<int>> recv_face_owner_by_proc(parallel::size());
-      for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-        recv_face_owner_by_proc[i_rank] = Array<int>(nb_face_to_recv_by_proc[i_rank]);
-      }
-      parallel::exchange(send_face_owner_by_proc, recv_face_owner_by_proc);
-
-      m_new_descriptor.face_owner_vector.resize(m_new_descriptor.face_number_vector.size());
-      for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-        for (size_t r=0; r<recv_face_owner_by_proc[i_rank].size(); ++r) {
-          const FaceId& face_id = recv_face_id_correspondance_by_proc[i_rank][r];
-          m_new_descriptor.face_owner_vector[face_id] = recv_face_owner_by_proc[i_rank][r];
-        }
-      }
-    }
-
-    std::vector<Array<int>> recv_face_number_of_node_by_proc(parallel::size());
-    {
-      const auto& face_to_node_matrix = m_connectivity.faceToNodeMatrix();
-      FaceValue<int> number_of_node_per_face(m_connectivity);
-      parallel_for(m_connectivity.numberOfFaces(), PASTIS_LAMBDA(const FaceId& j){
-          number_of_node_per_face[j] = face_to_node_matrix[j].size();
-        });
-
-      std::vector<Array<const int>> send_face_number_of_node_by_proc(parallel::size());
-      for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-        Array<int> send_face_number_of_node(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_number_of_node[l] = number_of_node_per_face[face_id];
-          });
-        send_face_number_of_node_by_proc[i_rank] = send_face_number_of_node;
-      }
+    std::vector<Array<const int>> recv_number_of_node_per_face_by_proc =
+        _getRecvNumberOfSubItemPerItemByProc<SubNodeOfFace>();
 
-      for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-        recv_face_number_of_node_by_proc[i_rank] = Array<int>(nb_face_to_recv_by_proc[i_rank]);
-      }
-      parallel::exchange(send_face_number_of_node_by_proc, recv_face_number_of_node_by_proc);
-    }
+    std::vector<Array<const int>> recv_face_node_numbering_by_proc
+        = this->_getRecvItemSubItemNumberingByProc<SubNodeOfFace>(recv_number_of_node_per_face_by_proc);
 
-    std::vector<Array<int>> face_node_number_to_send_by_proc(parallel::size());
     {
-      const auto& face_to_node_matrix = m_connectivity.faceToNodeMatrix();
-      const NodeValue<const int>& node_number = m_connectivity.nodeNumber();
-      for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-        std::vector<int> node_number_by_face_vector;
-        for (size_t l=0; l<send_face_id_by_proc[i_rank].size(); ++l) {
-          const FaceId& face_id = send_face_id_by_proc[i_rank][l];
-          const auto& face_node_list = face_to_node_matrix[face_id];
-          for (size_t r=0; r<face_node_list.size(); ++r) {
-            const NodeId& node_id = face_node_list[r];
-            node_number_by_face_vector.push_back(node_number[node_id]);
-          }
-        }
-        face_node_number_to_send_by_proc[i_rank] = convert_to_array(node_number_by_face_vector);
-      }
-    }
-
-    {
-      std::vector<Array<int>> recv_face_node_number_by_proc(parallel::size());
-      for (size_t i_rank=0; i_rank < parallel::size(); ++i_rank) {
-        recv_face_node_number_by_proc[i_rank]
-            = Array<int>(sum(recv_face_number_of_node_by_proc[i_rank]));
-      }
-
-      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) {
+        for (size_t i=0; i<recv_number_of_node_per_face_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 = node_number_id_map.find(recv_face_node_number_by_proc[i_rank][l++]);
+          for (int k=0; k<recv_number_of_node_per_face_by_proc[i_rank][i]; ++k) {
+            const auto& searched_node_id = node_number_id_map.find(recv_face_node_numbering_by_proc[i_rank][l++]);
             Assert(searched_node_id != node_number_id_map.end());
             node_vector.push_back(searched_node_id->second);
           }
@@ -661,6 +520,7 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
             }
           }
 
+          const auto& send_face_id_by_proc = m_dispatched_face_info.m_list_to_send_by_proc;
           std::vector<Array<const block_type>> send_face_refs_by_proc(parallel::size());
           for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
             Array<block_type> send_face_refs(nb_face_to_send_by_proc[i_rank]);
@@ -674,10 +534,11 @@ ConnectivityDispatcher<Dimension>::_dispatchFaces()
 
           std::vector<Array<block_type>> recv_face_refs_by_proc(parallel::size());
           for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-            recv_face_refs_by_proc[i_rank] = Array<block_type>(nb_face_to_recv_by_proc[i_rank]);
+            recv_face_refs_by_proc[i_rank] = Array<block_type>(m_dispatched_face_info.m_list_to_recv_size_by_proc[i_rank]);
           }
           parallel::exchange(send_face_refs_by_proc, recv_face_refs_by_proc);
 
+          const auto& recv_face_id_correspondance_by_proc = m_dispatched_face_info.m_recv_id_correspondance_by_proc;
           std::vector<block_type> face_refs(m_new_descriptor.face_number_vector.size());
           for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
             for (size_t r=0; r<recv_face_refs_by_proc[i_rank].size(); ++r) {
@@ -721,13 +582,11 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
   // this->_buildNewOwner<ItemType::edge>();
   this->_buildNewOwner<ItemType::node>();
 
-  m_dispatched_cell_info.m_list_to_send_by_proc = this->_buildCellListToSend();
+  this->_buildItemListToSend<ItemType::cell>();
   this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc
       = parallel::allToAll(this->_buildNbCellToSend());
 
-  m_recv_cell_number_by_proc = this->exchange(m_connectivity.cellNumber());
-  this->_dispatchedInfo<ItemType::cell>().m_number_to_id_map
-      = this->_buildCellNumberIdMap();
+  this->_buildCellNumberIdMap();
 
   const std::vector<Array<const int>> recv_number_of_node_per_cell_by_proc
       = this->_getRecvNumberOfSubItemPerItemByProc<SubNodeOfCell>();
@@ -735,19 +594,11 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
   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_numbering_by_proc);
-  this->_dispatchedInfo<ItemType::node>().m_number_to_id_map
-      = this->_buildNodeNumberIdMap(recv_cell_node_numbering_by_proc);
-
-  {
-    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;
-    }
-  }
+  this->_buildRecvItemIdCorrespondanceByProc<ItemType::cell>();
+  this->_gatherFrom(m_connectivity.template number<ItemType::cell>(), m_new_descriptor.cell_number_vector);
 
-  m_dispatched_node_info.m_list_to_send_by_proc = this->_buildNodeListToSend();
+  this->_buildSubItemNumberIdMapAs<SubNodeOfCell>(recv_cell_node_numbering_by_proc);
+  this->_buildItemListToSend<ItemType::node>();
 
   Array<unsigned int> nb_node_to_send_by_proc(parallel::size());
   for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
@@ -762,45 +613,10 @@ ConnectivityDispatcher<Dimension>::ConnectivityDispatcher(const ConnectivityType
   this->_gatherFrom(m_connectivity.cellType(), m_new_descriptor.cell_type_vector);
   this->_gatherFrom(this->_dispatchedInfo<ItemType::cell>().m_new_owner, m_new_descriptor.cell_owner_vector);
 
-  {
-    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_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] = 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>(node_list_to_recv_size_by_proc[i_rank]);
-    }
-    parallel::exchange(send_node_owner_by_proc, recv_node_owner_by_proc);
-
-    m_new_descriptor.node_owner_vector.resize(m_new_descriptor.node_number_vector.size());
-    for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) {
-      for (size_t r=0; r<recv_node_owner_by_proc[i_rank].size(); ++r) {
-        const NodeId& node_id = m_recv_node_id_correspondance_by_proc[i_rank][r];
-        m_new_descriptor.node_owner_vector[node_id] = recv_node_owner_by_proc[i_rank][r];
-      }
-    }
-  }
+  this->_gatherFrom(m_connectivity.template number<ItemType::node>(), m_new_descriptor.node_number_vector);
+  this->_gatherFrom(this->_dispatchedInfo<ItemType::node>().m_new_owner, m_new_descriptor.node_owner_vector);
 
-  {
+  { // build cells connectivity
     const auto& cell_list_to_recv_size_by_proc =
         this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
 
diff --git a/src/mesh/ConnectivityDispatcher.hpp b/src/mesh/ConnectivityDispatcher.hpp
index c68e3f857d38b99429cd31addf10936679921295..16a6b73ccd89bf15e70950e64d7ee8b72021e75a 100644
--- a/src/mesh/ConnectivityDispatcher.hpp
+++ b/src/mesh/ConnectivityDispatcher.hpp
@@ -65,30 +65,24 @@ class ConnectivityDispatcher
     }
   }
 
-  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;
-
   template <ItemType item_type>
   void _buildNewOwner();
 
-  std::vector<Array<const CellId>> _buildCellListToSend();
-
-  std::vector<Array<const NodeId>> _buildNodeListToSend();
+  template <ItemType item_type>
+  void _buildItemListToSend();
 
   Array<const unsigned int> _buildNbCellToSend();
 
-  std::unordered_map<int, int> _buildCellNumberIdMap();
+  void _buildCellNumberIdMap();
 
-  std::unordered_map<int, int>
-  _buildNodeNumberIdMap(const std::vector<Array<const int>>& recv_cell_node_number_by_proc);
+  template <typename SubItemOfItemT>
+  void _buildSubItemNumberIdMapAs(const std::vector<Array<const int>>& recv_cell_node_number_by_proc);
 
   void _dispatchFaces();
 
-  template <typename CellValueType,
-            typename DataType>
-  void _gatherFrom(const CellValueType& data_to_gather,
-                   std::vector<DataType>& gathered_vector);
+  template<typename DataType, ItemType item_type, typename ConnectivityPtr>
+  void _gatherFrom(const ItemValue<DataType, item_type, ConnectivityPtr>& data_to_gather,
+                   std::vector<std::remove_const_t<DataType>>& gathered_vector);
 
   template <typename SubItemOfItemT>
   std::vector<Array<const int>>
@@ -108,39 +102,40 @@ class ConnectivityDispatcher
     return m_dispatched_connectivity;
   }
 
-  template<typename DataType, typename ConnectivityPtr>
+  template<typename DataType, ItemType item_type, typename ConnectivityPtr>
   std::vector<Array<const DataType>>
-  exchange(ItemValue<DataType, ItemType::cell, ConnectivityPtr> cell_value) const
+  exchange(ItemValue<DataType, item_type, ConnectivityPtr> item_value) const
   {
+    using ItemId = ItemIdT<item_type>;
     using MutableDataType = std::remove_const_t<DataType>;
-    std::vector<Array<const DataType>> cell_value_to_send_by_proc(parallel::size());
+    std::vector<Array<const DataType>> item_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;
+    const auto& item_list_to_send_by_proc = this->_dispatchedInfo<item_type>().m_list_to_send_by_proc;
 
     for (size_t i=0; i<parallel::size(); ++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]];
+      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]];
         });
-      cell_value_to_send_by_proc[i] = cell_value_list;
+      item_value_to_send_by_proc[i] = item_value_list;
     }
 
-    std::vector<Array<MutableDataType>> recv_cell_value_by_proc(parallel::size());
+    std::vector<Array<MutableDataType>> recv_item_value_by_proc(parallel::size());
     {
-      const auto& list_to_recv_size_by_proc = this->_dispatchedInfo<ItemType::cell>().m_list_to_recv_size_by_proc;
+      const auto& list_to_recv_size_by_proc = this->_dispatchedInfo<item_type>().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]);
+        recv_item_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);
+    parallel::exchange(item_value_to_send_by_proc, recv_item_value_by_proc);
 
-    std::vector<Array<const DataType>> const_recv_cell_value_by_proc(parallel::size());
+    std::vector<Array<const DataType>> const_recv_item_value_by_proc(parallel::size());
     for (size_t i=0; i<parallel::size(); ++i) {
-      const_recv_cell_value_by_proc[i] = recv_cell_value_by_proc[i];
+      const_recv_item_value_by_proc[i] = recv_item_value_by_proc[i];
     }
 
-    return const_recv_cell_value_by_proc;
+    return const_recv_item_value_by_proc;
   }
 
   template<typename DataType, ItemType item_type, typename ConnectivityPtr>
diff --git a/src/mesh/SubItemOfItemType.hpp b/src/mesh/SubItemOfItemType.hpp
index dbf38255935bdafbc4d632e138e865910085da24..c2c8f267af4c9e782d6c15e3a28980936d7bb6b2 100644
--- a/src/mesh/SubItemOfItemType.hpp
+++ b/src/mesh/SubItemOfItemType.hpp
@@ -3,6 +3,7 @@
 
 #include <ItemType.hpp>
 
+#warning Should use this type in all sub item constructions
 template <ItemType sub_item_t,
           ItemType item_t>
 struct SubItemOfItemType