From 406bd0cc6f878fedf1ef641f15480ce636fa7054 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Thu, 10 Mar 2022 16:22:38 +0100
Subject: [PATCH] Rework item local numbers in their sub-items

All possible values are now filled using adequate types.

For instance in 1d, since nodes, edges and faces designate the same
entities, the following values are defined: nodes<->cells,
edges<->cells and faces<->cells. Actually, in that case, the same
memory (embedded Array) is used for all these data.

In 2d, only faces and edges share the same data.
---
 src/mesh/Connectivity.hpp         | 142 +++++++-------
 src/mesh/ConnectivityComputer.cpp | 248 ++++++++++++++++++------
 src/mesh/ConnectivityComputer.hpp |   3 +-
 src/mesh/ItemToItemMatrix.hpp     |   8 +
 tests/test_Connectivity.cpp       | 301 ++++++++++++++++++++++++++++++
 5 files changed, 574 insertions(+), 128 deletions(-)

diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp
index 3ec986e8b..86b6606c7 100644
--- a/src/mesh/Connectivity.hpp
+++ b/src/mesh/Connectivity.hpp
@@ -80,21 +80,21 @@ class Connectivity final : public IConnectivity
   WeakFaceValuePerCell<const bool> m_cell_face_is_reversed;
   WeakEdgeValuePerFace<const bool> m_face_edge_is_reversed;
 
-  WeakFaceValuePerCell<const unsigned short> m_cell_local_numbers_in_their_faces;
-  WeakEdgeValuePerCell<const unsigned short> m_cell_local_numbers_in_their_edges;
-  WeakNodeValuePerCell<const unsigned short> m_cell_local_numbers_in_their_nodes;
+  WeakFaceValuePerCell<const uint16_t> m_cell_local_numbers_in_their_faces;
+  WeakEdgeValuePerCell<const uint16_t> m_cell_local_numbers_in_their_edges;
+  WeakNodeValuePerCell<const uint16_t> m_cell_local_numbers_in_their_nodes;
 
-  WeakCellValuePerFace<const unsigned short> m_face_local_numbers_in_their_cells;
-  WeakEdgeValuePerFace<const unsigned short> m_face_local_numbers_in_their_edges;
-  WeakNodeValuePerFace<const unsigned short> m_face_local_numbers_in_their_nodes;
+  WeakCellValuePerFace<const uint16_t> m_face_local_numbers_in_their_cells;
+  WeakEdgeValuePerFace<const uint16_t> m_face_local_numbers_in_their_edges;
+  WeakNodeValuePerFace<const uint16_t> m_face_local_numbers_in_their_nodes;
 
-  WeakCellValuePerEdge<const unsigned short> m_edge_local_numbers_in_their_cells;
-  WeakFaceValuePerEdge<const unsigned short> m_edge_local_numbers_in_their_faces;
-  WeakNodeValuePerEdge<const unsigned short> m_edge_local_numbers_in_their_nodes;
+  WeakCellValuePerEdge<const uint16_t> m_edge_local_numbers_in_their_cells;
+  WeakFaceValuePerEdge<const uint16_t> m_edge_local_numbers_in_their_faces;
+  WeakNodeValuePerEdge<const uint16_t> m_edge_local_numbers_in_their_nodes;
 
-  WeakCellValuePerNode<const unsigned short> m_node_local_numbers_in_their_cells;
-  WeakFaceValuePerNode<const unsigned short> m_node_local_numbers_in_their_faces;
-  WeakEdgeValuePerNode<const unsigned short> m_node_local_numbers_in_their_edges;
+  WeakCellValuePerNode<const uint16_t> m_node_local_numbers_in_their_cells;
+  WeakFaceValuePerNode<const uint16_t> m_node_local_numbers_in_their_faces;
+  WeakEdgeValuePerNode<const uint16_t> m_node_local_numbers_in_their_edges;
 
   ConnectivityComputer m_connectivity_computer;
 
@@ -109,18 +109,6 @@ class Connectivity final : public IConnectivity
   void _buildIsBoundaryEdge() const;
   void _buildIsBoundaryNode() const;
 
-  template <typename SubItemValuePerItemType>
-  PUGS_INLINE const SubItemValuePerItemType&
-  _lazzyBuildItemNumberInTheirChild(const SubItemValuePerItemType& sub_item_value_per_item) const
-  {
-    using ReversedItemOfItem = typename SubItemValuePerItemType::ItemOfItemType::Reversed;
-    if (not sub_item_value_per_item.isBuilt()) {
-      const_cast<SubItemValuePerItemType&>(sub_item_value_per_item) =
-        m_connectivity_computer.computeLocalItemNumberInChildItem<ReversedItemOfItem>(*this);
-    }
-    return sub_item_value_per_item;
-  }
-
   friend class ConnectivityComputer;
 
  public:
@@ -446,109 +434,129 @@ class Connectivity final : public IConnectivity
   }
 
   PUGS_INLINE
-  const auto&
-  cellLocalNumbersInTheirNodes() const
+  FaceValuePerCell<const uint16_t>
+  cellLocalNumbersInTheirFaces() const
   {
-    return _lazzyBuildItemNumberInTheirChild(m_cell_local_numbers_in_their_nodes);
+    if (not m_cell_local_numbers_in_their_faces.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<FaceOfCell>(*this);
+    }
+    return m_cell_local_numbers_in_their_faces;
   }
 
   PUGS_INLINE
-  const auto&
+  EdgeValuePerCell<const uint16_t>
   cellLocalNumbersInTheirEdges() const
   {
-    if constexpr (Dimension > 2) {
-      return _lazzyBuildItemNumberInTheirChild(m_cell_local_numbers_in_their_edges);
-    } else {
-      return cellLocalNumbersInTheirFaces();
+    if (not m_cell_local_numbers_in_their_edges.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<EdgeOfCell>(*this);
     }
+    return m_cell_local_numbers_in_their_edges;
   }
 
   PUGS_INLINE
-  const auto&
-  cellLocalNumbersInTheirFaces() const
+  NodeValuePerCell<const uint16_t>
+  cellLocalNumbersInTheirNodes() const
   {
-    if constexpr (Dimension > 1) {
-      return _lazzyBuildItemNumberInTheirChild(m_cell_local_numbers_in_their_faces);
-    } else {
-      return cellLocalNumbersInTheirNodes();
+    if (not m_cell_local_numbers_in_their_nodes.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<NodeOfCell>(*this);
     }
+    return m_cell_local_numbers_in_their_nodes;
   }
 
   PUGS_INLINE
-  const auto&
+  CellValuePerFace<const uint16_t>
   faceLocalNumbersInTheirCells() const
   {
-    if constexpr (Dimension > 1) {
-      return _lazzyBuildItemNumberInTheirChild(m_face_local_numbers_in_their_cells);
-    } else {
-      return nodeLocalNumbersInTheirCells();
+    if (not m_face_local_numbers_in_their_cells.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<CellOfFace>(*this);
     }
+    return m_face_local_numbers_in_their_cells;
   }
 
   PUGS_INLINE
-  const auto&
+  EdgeValuePerFace<const uint16_t>
   faceLocalNumbersInTheirEdges() const
   {
     static_assert(Dimension > 2, "this function has no meaning in 1d or 2d");
-    return _lazzyBuildItemNumberInTheirChild(m_face_local_numbers_in_their_edges);
+    if (not m_face_local_numbers_in_their_edges.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<EdgeOfFace>(*this);
+    }
+    return m_face_local_numbers_in_their_edges;
   }
 
   PUGS_INLINE
-  const auto&
+  NodeValuePerFace<const uint16_t>
   faceLocalNumbersInTheirNodes() const
   {
     static_assert(Dimension > 1, "this function has no meaning in 1d");
-    return _lazzyBuildItemNumberInTheirChild(m_face_local_numbers_in_their_nodes);
+    if (not m_face_local_numbers_in_their_nodes.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<NodeOfFace>(*this);
+    }
+    return m_face_local_numbers_in_their_nodes;
   }
 
   PUGS_INLINE
-  const auto&
+  CellValuePerEdge<const uint16_t>
   edgeLocalNumbersInTheirCells() const
   {
-    if constexpr (Dimension > 2) {
-      return _lazzyBuildItemNumberInTheirChild(m_edge_local_numbers_in_their_cells);
-    } else {
-      return faceLocalNumbersInTheirCells();
+    if (not m_edge_local_numbers_in_their_cells.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<CellOfEdge>(*this);
     }
+    return m_edge_local_numbers_in_their_cells;
   }
 
   PUGS_INLINE
-  const auto&
+  FaceValuePerEdge<const uint16_t>
   edgeLocalNumbersInTheirFaces() const
   {
     static_assert(Dimension > 2, "this function has no meaning in 1d or 2d");
-    return _lazzyBuildItemNumberInTheirChild(m_edge_local_numbers_in_their_faces);
+    if (not m_edge_local_numbers_in_their_faces.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<FaceOfEdge>(*this);
+    }
+    return m_edge_local_numbers_in_their_faces;
   }
 
   PUGS_INLINE
-  const auto&
+  NodeValuePerEdge<const uint16_t>
   edgeLocalNumbersInTheirNodes() const
   {
-    static_assert(Dimension > 2, "this function has no meaning in 1d or 2d");
-    return _lazzyBuildItemNumberInTheirChild(m_edge_local_numbers_in_their_nodes);
+    static_assert(Dimension > 1, "this function has no meaning in 1d");
+    if (not m_edge_local_numbers_in_their_nodes.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<NodeOfEdge>(*this);
+    }
+    return m_edge_local_numbers_in_their_nodes;
   }
 
   PUGS_INLINE
-  const auto&
+  CellValuePerNode<const uint16_t>
   nodeLocalNumbersInTheirCells() const
   {
-    return _lazzyBuildItemNumberInTheirChild(m_node_local_numbers_in_their_cells);
+    if (not m_node_local_numbers_in_their_cells.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<CellOfNode>(*this);
+    }
+    return m_node_local_numbers_in_their_cells;
   }
 
   PUGS_INLINE
-  const auto&
-  nodeLocalNumbersInTheirEdges() const
+  FaceValuePerNode<const uint16_t>
+  nodeLocalNumbersInTheirFaces() const
   {
-    static_assert(Dimension > 2, "this function has no meaning in 1d or 2d");
-    return _lazzyBuildItemNumberInTheirChild(m_node_local_numbers_in_their_edges);
+    static_assert(Dimension > 1, "this function has no meaning in 1d");
+    if (not m_node_local_numbers_in_their_faces.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<FaceOfNode>(*this);
+    }
+    return m_node_local_numbers_in_their_faces;
   }
 
   PUGS_INLINE
-  const auto&
-  nodeLocalNumbersInTheirFaces() const
+  EdgeValuePerNode<const uint16_t>
+  nodeLocalNumbersInTheirEdges() const
   {
-    static_assert(Dimension > 1, "this function has no meaning in 1d");
-    return _lazzyBuildItemNumberInTheirChild(m_node_local_numbers_in_their_faces);
+    static_assert(Dimension > 1, "this function has no meaning in 1d or 2d");
+    if (not m_node_local_numbers_in_their_edges.isBuilt()) {
+      m_connectivity_computer.computeLocalItemNumberInChildItem<EdgeOfNode>(*this);
+    }
+    return m_node_local_numbers_in_their_edges;
   }
 
   template <ItemType item_type>
diff --git a/src/mesh/ConnectivityComputer.cpp b/src/mesh/ConnectivityComputer.cpp
index 7e8b32020..67463bb8a 100644
--- a/src/mesh/ConnectivityComputer.cpp
+++ b/src/mesh/ConnectivityComputer.cpp
@@ -73,98 +73,228 @@ ConnectivityComputer::_computeInverse(const ConnectivityMatrix& item_to_child_ma
 }
 
 template <typename ItemOfItem, typename ConnectivityType>
-WeakSubItemValuePerItem<const unsigned short, typename ItemOfItem::Reversed>
+void
 ConnectivityComputer::computeLocalItemNumberInChildItem(const ConnectivityType& connectivity) const
 {
-  using ReversedItemOfItem = typename ItemOfItem::Reversed;
+  constexpr ItemType item_type     = ItemOfItem::item_type;
+  constexpr ItemType sub_item_type = ItemOfItem::sub_item_type;
 
-  constexpr ItemType item_type       = ReversedItemOfItem::item_type;
-  constexpr ItemType child_item_type = ReversedItemOfItem::sub_item_type;
+  ItemToItemMatrix item_to_child_items_matrix = connectivity.template getItemToItemMatrix<item_type, sub_item_type>();
+  ItemToItemMatrix child_item_to_items_matrix = connectivity.template getItemToItemMatrix<sub_item_type, item_type>();
 
-  ItemToItemMatrix item_to_child_items_matrix = connectivity.template getItemToItemMatrix<item_type, child_item_type>();
-  ItemToItemMatrix child_item_to_items_matrix = connectivity.template getItemToItemMatrix<child_item_type, item_type>();
-
-  WeakSubItemValuePerItem<unsigned short, ReversedItemOfItem> item_number_in_child_item(connectivity);
-  for (ItemIdT<item_type> r = 0; r < connectivity.template numberOf<item_type>(); ++r) {
-    const auto& item_to_child_items = item_to_child_items_matrix[r];
-    for (unsigned short J = 0; J < item_to_child_items_matrix[r].size(); ++J) {
-      ItemIdT j                       = item_to_child_items[J];
-      const auto& child_item_to_items = child_item_to_items_matrix[j];
-
-      for (unsigned int R = 0; R < child_item_to_items.size(); ++R) {
-        if (child_item_to_items[R] == r) {
-          item_number_in_child_item(r, J) = R;
-          break;
+  Array<unsigned short> number_in_child_array{item_to_child_items_matrix.numberOfValues()};
+  {
+    WeakSubItemValuePerItem<unsigned short, ItemOfItem> item_number_in_child_item(connectivity, number_in_child_array);
+    for (ItemIdT<item_type> item_id = 0; item_id < connectivity.template numberOf<item_type>(); ++item_id) {
+      const auto& item_to_child_items = item_to_child_items_matrix[item_id];
+      for (unsigned short i_item_child = 0; i_item_child < item_to_child_items_matrix[item_id].size(); ++i_item_child) {
+        ItemIdT j                       = item_to_child_items[i_item_child];
+        const auto& child_item_to_items = child_item_to_items_matrix[j];
+
+        for (unsigned int i_item_in_child = 0; i_item_in_child < child_item_to_items.size(); ++i_item_in_child) {
+          if (child_item_to_items[i_item_in_child] == item_id) {
+            item_number_in_child_item(item_id, i_item_child) = i_item_in_child;
+            break;
+          }
         }
       }
     }
   }
 
-  return item_number_in_child_item;
+  if constexpr (ConnectivityType::Dimension == 1) {
+    if constexpr (item_type == ItemType::cell) {
+      const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfCell>&>(
+        connectivity.m_cell_local_numbers_in_their_faces) =
+        WeakSubItemValuePerItem<unsigned short, FaceOfCell>(connectivity, number_in_child_array);
+      const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfCell>&>(
+        connectivity.m_cell_local_numbers_in_their_edges) =
+        WeakSubItemValuePerItem<unsigned short, EdgeOfCell>(connectivity, number_in_child_array);
+      const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfCell>&>(
+        connectivity.m_cell_local_numbers_in_their_nodes) =
+        WeakSubItemValuePerItem<unsigned short, NodeOfCell>(connectivity, number_in_child_array);
+    } else if constexpr (sub_item_type == ItemType::cell) {
+      const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfFace>&>(
+        connectivity.m_face_local_numbers_in_their_cells) =
+        WeakSubItemValuePerItem<unsigned short, CellOfFace>(connectivity, number_in_child_array);
+      const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfEdge>&>(
+        connectivity.m_edge_local_numbers_in_their_cells) =
+        WeakSubItemValuePerItem<unsigned short, CellOfEdge>(connectivity, number_in_child_array);
+      const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfNode>&>(
+        connectivity.m_node_local_numbers_in_their_cells) =
+        WeakSubItemValuePerItem<unsigned short, CellOfNode>(connectivity, number_in_child_array);
+    }
+  } else if constexpr (ConnectivityType::Dimension == 2) {
+    if constexpr (item_type == ItemType::cell) {
+      if constexpr ((sub_item_type == ItemType::face) or (sub_item_type == ItemType::edge)) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_faces) =
+          WeakSubItemValuePerItem<unsigned short, FaceOfCell>(connectivity, number_in_child_array);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_edges) =
+          WeakSubItemValuePerItem<unsigned short, EdgeOfCell>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::node);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfCell>(connectivity, number_in_child_array);
+      }
+    } else if constexpr (item_type == ItemType::face or item_type == ItemType::edge) {
+      if constexpr (sub_item_type == ItemType::cell) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfFace>&>(
+          connectivity.m_face_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfFace>(connectivity, number_in_child_array);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfEdge>&>(
+          connectivity.m_edge_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfEdge>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::node);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfFace>&>(
+          connectivity.m_face_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfFace>(connectivity, number_in_child_array);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfEdge>&>(
+          connectivity.m_edge_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfEdge>(connectivity, number_in_child_array);
+      }
+    } else {
+      static_assert(item_type == ItemType::node);
+      if constexpr (sub_item_type == ItemType::cell) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfNode>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::face or sub_item_type == ItemType::edge);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_faces) =
+          WeakSubItemValuePerItem<unsigned short, FaceOfNode>(connectivity, number_in_child_array);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_edges) =
+          WeakSubItemValuePerItem<unsigned short, EdgeOfNode>(connectivity, number_in_child_array);
+      }
+    }
+  } else if constexpr (ConnectivityType::Dimension == 3) {
+    if constexpr (item_type == ItemType::cell) {
+      if constexpr (sub_item_type == ItemType::face) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_faces) =
+          WeakSubItemValuePerItem<unsigned short, FaceOfCell>(connectivity, number_in_child_array);
+      } else if constexpr (sub_item_type == ItemType::edge) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_edges) =
+          WeakSubItemValuePerItem<unsigned short, EdgeOfCell>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::node);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfCell>&>(
+          connectivity.m_cell_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfCell>(connectivity, number_in_child_array);
+      }
+    } else if constexpr (item_type == ItemType::face) {
+      if constexpr (sub_item_type == ItemType::cell) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfFace>&>(
+          connectivity.m_face_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfFace>(connectivity, number_in_child_array);
+      } else if constexpr (sub_item_type == ItemType::edge) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfFace>&>(
+          connectivity.m_face_local_numbers_in_their_edges) =
+          WeakSubItemValuePerItem<unsigned short, EdgeOfFace>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::node);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfFace>&>(
+          connectivity.m_face_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfFace>(connectivity, number_in_child_array);
+      }
+    } else if constexpr (item_type == ItemType::edge) {
+      if constexpr (sub_item_type == ItemType::cell) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfEdge>&>(
+          connectivity.m_edge_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfEdge>(connectivity, number_in_child_array);
+      } else if constexpr (sub_item_type == ItemType::face) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfEdge>&>(
+          connectivity.m_edge_local_numbers_in_their_faces) =
+          WeakSubItemValuePerItem<unsigned short, FaceOfEdge>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::node);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, NodeOfEdge>&>(
+          connectivity.m_edge_local_numbers_in_their_nodes) =
+          WeakSubItemValuePerItem<unsigned short, NodeOfEdge>(connectivity, number_in_child_array);
+      }
+    } else {
+      static_assert(item_type == ItemType::node);
+      if constexpr (sub_item_type == ItemType::cell) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, CellOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_cells) =
+          WeakSubItemValuePerItem<unsigned short, CellOfNode>(connectivity, number_in_child_array);
+      } else if constexpr (sub_item_type == ItemType::face) {
+        const_cast<WeakSubItemValuePerItem<const unsigned short, FaceOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_faces) =
+          WeakSubItemValuePerItem<unsigned short, FaceOfNode>(connectivity, number_in_child_array);
+      } else {
+        static_assert(sub_item_type == ItemType::edge);
+        const_cast<WeakSubItemValuePerItem<const unsigned short, EdgeOfNode>&>(
+          connectivity.m_node_local_numbers_in_their_edges) =
+          WeakSubItemValuePerItem<unsigned short, EdgeOfNode>(connectivity, number_in_child_array);
+      }
+    }
+  }
 }
 
 // 1D
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity1D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfFace>(const Connectivity1D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfEdge>(const Connectivity1D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity1D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfCell>(const Connectivity1D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity1D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfCell>(const Connectivity1D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity1D&) const;
 
 // 2D
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfFace>(const Connectivity2D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfEdge>(const Connectivity2D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity2D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfCell>(const Connectivity2D&) const;
+
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfNode>(const Connectivity2D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfFace>
-ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfCell>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfCell>(const Connectivity2D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, FaceOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfFace>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfNode>(const Connectivity2D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, FaceOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfFace>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity2D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfFace>
-ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfNode>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfFace>(const Connectivity2D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity2D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfEdge>(const Connectivity2D&) const;
 
 // 3D
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfFace>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfEdge>
-ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfCell>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfEdge>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, CellOfFace>
-ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfCell>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, FaceOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfFace>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfCell>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, FaceOfEdge>
-ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfFace>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfEdge>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, FaceOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfFace>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfNode>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, EdgeOfNode>
-ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfEdge>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfCell>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, EdgeOfFace>
-ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfEdge>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfFace>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, EdgeOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfEdge>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfNode>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfEdge>
-ConnectivityComputer::computeLocalItemNumberInChildItem<EdgeOfNode>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfCell>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfFace>
-ConnectivityComputer::computeLocalItemNumberInChildItem<FaceOfNode>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfFace>(const Connectivity3D&) const;
 
-template WeakSubItemValuePerItem<const unsigned short, NodeOfCell>
-ConnectivityComputer::computeLocalItemNumberInChildItem<CellOfNode>(const Connectivity3D&) const;
+template void ConnectivityComputer::computeLocalItemNumberInChildItem<NodeOfEdge>(const Connectivity3D&) const;
diff --git a/src/mesh/ConnectivityComputer.hpp b/src/mesh/ConnectivityComputer.hpp
index a4f843e21..b033a25d5 100644
--- a/src/mesh/ConnectivityComputer.hpp
+++ b/src/mesh/ConnectivityComputer.hpp
@@ -16,8 +16,7 @@ class ConnectivityComputer
                                                ItemType child_item_type) const;
 
   template <typename ItemOfItem, typename ConnectivityType>
-  WeakSubItemValuePerItem<const unsigned short, typename ItemOfItem::Reversed> computeLocalItemNumberInChildItem(
-    const ConnectivityType& connectivity) const;
+  void computeLocalItemNumberInChildItem(const ConnectivityType& connectivity) const;
 
   ConnectivityComputer(const ConnectivityComputer&) = default;
   ConnectivityComputer()                            = default;
diff --git a/src/mesh/ItemToItemMatrix.hpp b/src/mesh/ItemToItemMatrix.hpp
index 8ee4e9d74..6cd2d798b 100644
--- a/src/mesh/ItemToItemMatrix.hpp
+++ b/src/mesh/ItemToItemMatrix.hpp
@@ -58,6 +58,14 @@ class ItemToItemMatrix
   const ConnectivityMatrix& m_connectivity_matrix;
 
  public:
+  PUGS_INLINE
+  size_t
+  numberOfValues() const
+  {
+    return m_connectivity_matrix.numberOfValues();
+  }
+
+  PUGS_INLINE
   auto
   values() const
   {
diff --git a/tests/test_Connectivity.cpp b/tests/test_Connectivity.cpp
index dcc979dd9..f7d2ab7de 100644
--- a/tests/test_Connectivity.cpp
+++ b/tests/test_Connectivity.cpp
@@ -669,4 +669,305 @@ TEST_CASE("Connectivity", "[mesh]")
       }
     }
   }
+
+  SECTION("ItemLocalNumbersInTheirSubItems")
+  {
+    auto check_item_local_numbers_in_their_subitems = [](auto item_to_subitem_matrix, auto subitem_to_item_matrix,
+                                                         auto item_local_numbers_in_subitems) -> bool {
+      using ItemId    = typename decltype(item_to_subitem_matrix)::SourceItemId;
+      using SubItemId = typename decltype(item_to_subitem_matrix)::TargetItemId;
+
+      static_assert(std::is_same_v<typename decltype(item_to_subitem_matrix)::SourceItemId,
+                                   typename decltype(subitem_to_item_matrix)::TargetItemId>);
+      static_assert(std::is_same_v<typename decltype(item_to_subitem_matrix)::TargetItemId,
+                                   typename decltype(subitem_to_item_matrix)::SourceItemId>);
+      static_assert(std::is_same_v<typename decltype(item_to_subitem_matrix)::SourceItemId,
+                                   typename decltype(item_local_numbers_in_subitems)::ItemId>);
+
+      for (ItemId item_id = 0; item_id < item_local_numbers_in_subitems.numberOfItems(); ++item_id) {
+        auto item_subitem_list = item_to_subitem_matrix[item_id];
+        auto item_numbers      = item_local_numbers_in_subitems.itemArray(item_id);
+
+        for (size_t i_item_subitem = 0; i_item_subitem < item_subitem_list.size(); ++i_item_subitem) {
+          const SubItemId node_cell_id = item_subitem_list[i_item_subitem];
+          const size_t i_local_item    = item_numbers[i_item_subitem];
+          if (subitem_to_item_matrix[node_cell_id][i_local_item] != item_id) {
+            return false;
+          }
+        }
+      }
+      return true;
+    };
+
+    SECTION("1D")
+    {
+      std::array mesh_list = MeshDataBaseForTests::get().all1DMeshes();
+
+      for (auto named_mesh : mesh_list) {
+        SECTION(named_mesh.name())
+        {
+          auto mesh                           = named_mesh.mesh();
+          const Connectivity<1>& connectivity = mesh->connectivity();
+
+          SECTION("node <-> cell")
+          {
+            auto node_to_cell_matrix = connectivity.nodeToCellMatrix();
+            auto cell_to_node_matrix = connectivity.cellToNodeMatrix();
+
+            auto node_local_numbers_in_their_cells = connectivity.nodeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_cell_matrix, cell_to_node_matrix,
+                                                               node_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_nodes = connectivity.cellLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_node_matrix, node_to_cell_matrix,
+                                                               cell_local_numbers_in_their_nodes));
+          }
+
+          SECTION("edge <-> cell")
+          {
+            auto edge_to_cell_matrix = connectivity.edgeToCellMatrix();
+            auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix();
+
+            auto edge_local_numbers_in_their_cells = connectivity.edgeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_cell_matrix, cell_to_edge_matrix,
+                                                               edge_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_edges = connectivity.cellLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_edge_matrix, edge_to_cell_matrix,
+                                                               cell_local_numbers_in_their_edges));
+          }
+
+          SECTION("face <-> cell")
+          {
+            auto face_to_cell_matrix = connectivity.faceToCellMatrix();
+            auto cell_to_face_matrix = connectivity.cellToFaceMatrix();
+
+            auto face_local_numbers_in_their_cells = connectivity.faceLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_cell_matrix, cell_to_face_matrix,
+                                                               face_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_faces = connectivity.cellLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_face_matrix, face_to_cell_matrix,
+                                                               cell_local_numbers_in_their_faces));
+          }
+
+          SECTION("shared data")
+          {
+            auto face_local_numbers_in_their_cells = connectivity.faceLocalNumbersInTheirCells();
+            auto edge_local_numbers_in_their_cells = connectivity.edgeLocalNumbersInTheirCells();
+            auto node_local_numbers_in_their_cells = connectivity.nodeLocalNumbersInTheirCells();
+
+            REQUIRE(&(face_local_numbers_in_their_cells[0]) == &(edge_local_numbers_in_their_cells[0]));
+            REQUIRE(&(face_local_numbers_in_their_cells[0]) == &(node_local_numbers_in_their_cells[0]));
+
+            auto cell_local_numbers_in_their_faces = connectivity.cellLocalNumbersInTheirFaces();
+            auto cell_local_numbers_in_their_edges = connectivity.cellLocalNumbersInTheirEdges();
+            auto cell_local_numbers_in_their_nodes = connectivity.cellLocalNumbersInTheirNodes();
+
+            REQUIRE(&(cell_local_numbers_in_their_faces[0]) == &(cell_local_numbers_in_their_edges[0]));
+            REQUIRE(&(cell_local_numbers_in_their_faces[0]) == &(cell_local_numbers_in_their_nodes[0]));
+          }
+        }
+      }
+    }
+
+    SECTION("2D")
+    {
+      std::array mesh_list = MeshDataBaseForTests::get().all2DMeshes();
+
+      for (auto named_mesh : mesh_list) {
+        SECTION(named_mesh.name())
+        {
+          auto mesh                           = named_mesh.mesh();
+          const Connectivity<2>& connectivity = mesh->connectivity();
+
+          SECTION("node <-> cell")
+          {
+            auto node_to_cell_matrix = connectivity.nodeToCellMatrix();
+            auto cell_to_node_matrix = connectivity.cellToNodeMatrix();
+
+            auto node_local_numbers_in_their_cells = connectivity.nodeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_cell_matrix, cell_to_node_matrix,
+                                                               node_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_nodes = connectivity.cellLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_node_matrix, node_to_cell_matrix,
+                                                               cell_local_numbers_in_their_nodes));
+          }
+
+          SECTION("edge <-> cell")
+          {
+            auto edge_to_cell_matrix = connectivity.edgeToCellMatrix();
+            auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix();
+
+            auto edge_local_numbers_in_their_cells = connectivity.edgeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_cell_matrix, cell_to_edge_matrix,
+                                                               edge_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_edges = connectivity.cellLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_edge_matrix, edge_to_cell_matrix,
+                                                               cell_local_numbers_in_their_edges));
+          }
+
+          SECTION("face <-> cell")
+          {
+            auto face_to_cell_matrix = connectivity.faceToCellMatrix();
+            auto cell_to_face_matrix = connectivity.cellToFaceMatrix();
+
+            auto face_local_numbers_in_their_cells = connectivity.faceLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_cell_matrix, cell_to_face_matrix,
+                                                               face_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_faces = connectivity.cellLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_face_matrix, face_to_cell_matrix,
+                                                               cell_local_numbers_in_their_faces));
+          }
+
+          SECTION("node <-> face")
+          {
+            auto node_to_face_matrix = connectivity.nodeToFaceMatrix();
+            auto face_to_node_matrix = connectivity.faceToNodeMatrix();
+
+            auto node_local_numbers_in_their_faces = connectivity.nodeLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_face_matrix, face_to_node_matrix,
+                                                               node_local_numbers_in_their_faces));
+
+            auto face_local_numbers_in_their_nodes = connectivity.faceLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_node_matrix, node_to_face_matrix,
+                                                               face_local_numbers_in_their_nodes));
+          }
+
+          SECTION("node <-> edge")
+          {
+            auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix();
+            auto edge_to_node_matrix = connectivity.edgeToNodeMatrix();
+
+            auto node_local_numbers_in_their_edges = connectivity.nodeLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_edge_matrix, edge_to_node_matrix,
+                                                               node_local_numbers_in_their_edges));
+
+            auto edge_local_numbers_in_their_nodes = connectivity.edgeLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_node_matrix, node_to_edge_matrix,
+                                                               edge_local_numbers_in_their_nodes));
+          }
+
+          SECTION("shared data")
+          {
+            auto face_local_numbers_in_their_cells = connectivity.faceLocalNumbersInTheirCells();
+            auto edge_local_numbers_in_their_cells = connectivity.edgeLocalNumbersInTheirCells();
+            auto face_local_numbers_in_their_nodes = connectivity.faceLocalNumbersInTheirNodes();
+            auto edge_local_numbers_in_their_nodes = connectivity.edgeLocalNumbersInTheirNodes();
+
+            REQUIRE(&(face_local_numbers_in_their_cells[0]) == &(edge_local_numbers_in_their_cells[0]));
+            REQUIRE(&(face_local_numbers_in_their_nodes[0]) == &(edge_local_numbers_in_their_nodes[0]));
+
+            auto cell_local_numbers_in_their_faces = connectivity.cellLocalNumbersInTheirFaces();
+            auto cell_local_numbers_in_their_edges = connectivity.cellLocalNumbersInTheirEdges();
+            auto node_local_numbers_in_their_faces = connectivity.nodeLocalNumbersInTheirFaces();
+            auto node_local_numbers_in_their_edges = connectivity.nodeLocalNumbersInTheirEdges();
+
+            REQUIRE(&(cell_local_numbers_in_their_faces[0]) == &(cell_local_numbers_in_their_edges[0]));
+            REQUIRE(&(node_local_numbers_in_their_faces[0]) == &(node_local_numbers_in_their_edges[0]));
+          }
+        }
+      }
+    }
+
+    SECTION("3D")
+    {
+      std::array mesh_list = MeshDataBaseForTests::get().all3DMeshes();
+
+      for (auto named_mesh : mesh_list) {
+        SECTION(named_mesh.name())
+        {
+          auto mesh                           = named_mesh.mesh();
+          const Connectivity<3>& connectivity = mesh->connectivity();
+
+          SECTION("node <-> cell")
+          {
+            auto node_to_cell_matrix = connectivity.nodeToCellMatrix();
+            auto cell_to_node_matrix = connectivity.cellToNodeMatrix();
+
+            auto node_local_numbers_in_their_cells = connectivity.nodeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_cell_matrix, cell_to_node_matrix,
+                                                               node_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_nodes = connectivity.cellLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_node_matrix, node_to_cell_matrix,
+                                                               cell_local_numbers_in_their_nodes));
+          }
+
+          SECTION("edge <-> cell")
+          {
+            auto edge_to_cell_matrix = connectivity.edgeToCellMatrix();
+            auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix();
+
+            auto edge_local_numbers_in_their_cells = connectivity.edgeLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_cell_matrix, cell_to_edge_matrix,
+                                                               edge_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_edges = connectivity.cellLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_edge_matrix, edge_to_cell_matrix,
+                                                               cell_local_numbers_in_their_edges));
+          }
+
+          SECTION("face <-> cell")
+          {
+            auto face_to_cell_matrix = connectivity.faceToCellMatrix();
+            auto cell_to_face_matrix = connectivity.cellToFaceMatrix();
+
+            auto face_local_numbers_in_their_cells = connectivity.faceLocalNumbersInTheirCells();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_cell_matrix, cell_to_face_matrix,
+                                                               face_local_numbers_in_their_cells));
+
+            auto cell_local_numbers_in_their_faces = connectivity.cellLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(cell_to_face_matrix, face_to_cell_matrix,
+                                                               cell_local_numbers_in_their_faces));
+          }
+
+          SECTION("node <-> face")
+          {
+            auto node_to_face_matrix = connectivity.nodeToFaceMatrix();
+            auto face_to_node_matrix = connectivity.faceToNodeMatrix();
+
+            auto node_local_numbers_in_their_faces = connectivity.nodeLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_face_matrix, face_to_node_matrix,
+                                                               node_local_numbers_in_their_faces));
+
+            auto face_local_numbers_in_their_nodes = connectivity.faceLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_node_matrix, node_to_face_matrix,
+                                                               face_local_numbers_in_their_nodes));
+          }
+
+          SECTION("edge <-> face")
+          {
+            auto edge_to_face_matrix = connectivity.edgeToFaceMatrix();
+            auto face_to_edge_matrix = connectivity.faceToEdgeMatrix();
+
+            auto edge_local_numbers_in_their_faces = connectivity.edgeLocalNumbersInTheirFaces();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_face_matrix, face_to_edge_matrix,
+                                                               edge_local_numbers_in_their_faces));
+
+            auto face_local_numbers_in_their_edges = connectivity.faceLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(face_to_edge_matrix, edge_to_face_matrix,
+                                                               face_local_numbers_in_their_edges));
+          }
+
+          SECTION("node <-> edge")
+          {
+            auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix();
+            auto edge_to_node_matrix = connectivity.edgeToNodeMatrix();
+
+            auto node_local_numbers_in_their_edges = connectivity.nodeLocalNumbersInTheirEdges();
+            REQUIRE(check_item_local_numbers_in_their_subitems(node_to_edge_matrix, edge_to_node_matrix,
+                                                               node_local_numbers_in_their_edges));
+
+            auto edge_local_numbers_in_their_nodes = connectivity.edgeLocalNumbersInTheirNodes();
+            REQUIRE(check_item_local_numbers_in_their_subitems(edge_to_node_matrix, node_to_edge_matrix,
+                                                               edge_local_numbers_in_their_nodes));
+          }
+        }
+      }
+    }
+  }
 }
-- 
GitLab