diff --git a/src/mesh/ItemArray.hpp b/src/mesh/ItemArray.hpp
index f47835b7cd14f30a7c3c85283f3a8b33a8e5161a..a38f950954084a3527717a2a858d452e3e3cf2ad 100644
--- a/src/mesh/ItemArray.hpp
+++ b/src/mesh/ItemArray.hpp
@@ -33,13 +33,13 @@ class ItemArray
 
   size_t m_size_of_arrays;
 
- public:
   // Allow const std:shared_ptr version to access our data
   friend ItemArray<std::add_const_t<DataType>, item_type, ConnectivitySharedPtr>;
 
   // Allow const std:weak_ptr version to access our data
   friend ItemArray<std::add_const_t<DataType>, item_type, ConnectivityWeakPtr>;
 
+ public:
   friend PUGS_INLINE ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityPtr>
   copy(const ItemArray<DataType, item_type, ConnectivityPtr>& source)
   {
diff --git a/src/mesh/ItemArrayUtils.hpp b/src/mesh/ItemArrayUtils.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..618dc8c8e061e55f9db3950b7cff71b3b281b111
--- /dev/null
+++ b/src/mesh/ItemArrayUtils.hpp
@@ -0,0 +1,26 @@
+#ifndef ITEM_ARRAY_UTILS_HPP
+#define ITEM_ARRAY_UTILS_HPP
+
+#include <utils/Messenger.hpp>
+
+#include <mesh/Connectivity.hpp>
+#include <mesh/ItemArray.hpp>
+#include <mesh/Synchronizer.hpp>
+#include <mesh/SynchronizerManager.hpp>
+
+#include <iostream>
+
+template <typename DataType, ItemType item_type, typename ConnectivityPtr>
+void
+synchronize(ItemArray<DataType, item_type, ConnectivityPtr>& item_array)
+{
+  static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemArray of const data");
+  if (parallel::size() > 1) {
+    auto& manager                     = SynchronizerManager::instance();
+    const IConnectivity* connectivity = item_array.connectivity_ptr().get();
+    Synchronizer& synchronizer        = manager.getConnectivitySynchronizer(connectivity);
+    synchronizer.synchronize(item_array);
+  }
+}
+
+#endif   // ITEM_ARRAY_UTILS_HPP
diff --git a/src/mesh/ItemValue.hpp b/src/mesh/ItemValue.hpp
index d39421c5c3a89acd77c500af1f4d92f49ff4d958..0f7fe61717fc9d8c571d0107b5ae422cc6b911bb 100644
--- a/src/mesh/ItemValue.hpp
+++ b/src/mesh/ItemValue.hpp
@@ -1,12 +1,11 @@
 #ifndef ITEM_VALUE_HPP
 #define ITEM_VALUE_HPP
 
-#include <utils/Array.hpp>
-#include <utils/PugsAssert.hpp>
-
 #include <mesh/IConnectivity.hpp>
 #include <mesh/ItemId.hpp>
 #include <mesh/ItemType.hpp>
+#include <utils/Array.hpp>
+#include <utils/PugsAssert.hpp>
 
 #include <memory>
 
diff --git a/src/mesh/Synchronizer.hpp b/src/mesh/Synchronizer.hpp
index 209ea0f4702430df0b93e3ef662ffc30c82300fd..adf127f238fc201a11ba5b503aed4b926e772a4d 100644
--- a/src/mesh/Synchronizer.hpp
+++ b/src/mesh/Synchronizer.hpp
@@ -2,6 +2,7 @@
 #define SYNCHRONIZER_HPP
 
 #include <mesh/Connectivity.hpp>
+#include <mesh/ItemArray.hpp>
 #include <mesh/ItemValue.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/Messenger.hpp>
@@ -168,6 +169,62 @@ class Synchronizer
     }
   }
 
+  template <typename ConnectivityType, typename DataType, ItemType item_type, typename ConnectivityPtr>
+  PUGS_INLINE void
+  _synchronize(const ConnectivityType& connectivity, ItemArray<DataType, item_type, ConnectivityPtr>& item_array)
+  {
+    static_assert(not std::is_abstract_v<ConnectivityType>, "_synchronize must be called on a concrete connectivity");
+
+    using ItemId = ItemIdT<item_type>;
+
+    const auto& provided_item_info  = this->_getProvidedItemInfo<item_type>();
+    const auto& requested_item_info = this->_getRequestedItemInfo<item_type>();
+
+    Assert(requested_item_info.size() == provided_item_info.size());
+
+    if (provided_item_info.size() == 0) {
+      this->_buildSynchronizeInfo<ConnectivityType, item_type>(connectivity);
+    }
+
+    const size_t size_of_arrays = item_array.sizeOfArrays();
+
+    std::vector<Array<const DataType>> provided_data_list(parallel::size());
+    for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
+      const Array<const ItemId>& provided_item_info_to_rank = provided_item_info[i_rank];
+      Array<DataType> provided_data{provided_item_info_to_rank.size() * size_of_arrays};
+      parallel_for(
+        provided_item_info_to_rank.size(), PUGS_LAMBDA(size_t i) {
+          const size_t j   = i * size_of_arrays;
+          const auto array = item_array[provided_item_info_to_rank[i]];
+          for (size_t k = 0; k < size_of_arrays; ++k) {
+            provided_data[j + k] = array[k];
+          }
+        });
+      provided_data_list[i_rank] = provided_data;
+    }
+
+    std::vector<Array<DataType>> requested_data_list(parallel::size());
+    for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
+      const auto& requested_item_info_from_rank = requested_item_info[i_rank];
+      requested_data_list[i_rank] = Array<DataType>{requested_item_info_from_rank.size() * size_of_arrays};
+    }
+
+    parallel::exchange(provided_data_list, requested_data_list);
+
+    for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
+      const auto& requested_item_info_from_rank = requested_item_info[i_rank];
+      const auto& requested_data                = requested_data_list[i_rank];
+      parallel_for(
+        requested_item_info_from_rank.size(), PUGS_LAMBDA(size_t i) {
+          const size_t j = i * size_of_arrays;
+          auto array     = item_array[requested_item_info_from_rank[i]];
+          for (size_t k = 0; k < size_of_arrays; ++k) {
+            array[k] = requested_data[j + k];
+          }
+        });
+    }
+  }
+
  public:
   template <typename DataType, ItemType item_type, typename ConnectivityPtr>
   PUGS_INLINE void
@@ -189,9 +246,39 @@ class Synchronizer
       this->_synchronize(static_cast<const Connectivity3D&>(connectivity), item_value);
       break;
     }
+      // LCOV_EXCL_START
+    default: {
+      throw UnexpectedError("unexpected dimension");
+    }
+      // LCOV_EXCL_STOP
+    }
+  }
+
+  template <typename DataType, ItemType item_type, typename ConnectivityPtr>
+  PUGS_INLINE void
+  synchronize(ItemArray<DataType, item_type, ConnectivityPtr>& item_value)
+  {
+    Assert(item_value.connectivity_ptr().use_count() > 0, "No connectivity is associated to this ItemValue");
+    const IConnectivity& connectivity = *item_value.connectivity_ptr();
+
+    switch (connectivity.dimension()) {
+    case 1: {
+      this->_synchronize(static_cast<const Connectivity1D&>(connectivity), item_value);
+      break;
+    }
+    case 2: {
+      this->_synchronize(static_cast<const Connectivity2D&>(connectivity), item_value);
+      break;
+    }
+    case 3: {
+      this->_synchronize(static_cast<const Connectivity3D&>(connectivity), item_value);
+      break;
+    }
+      // LCOV_EXCL_START
     default: {
       throw UnexpectedError("unexpected dimension");
     }
+      // LCOV_EXCL_STOP
     }
   }
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 976258f59c8c3749cac81210b3c1a6a1c5a9f581..6f255448f4cdf002bc0d0df0a795bbca26935efe 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -101,6 +101,7 @@ add_executable (mpi_unit_tests
   test_Messenger.cpp
   test_Partitioner.cpp
   test_ItemArray.cpp
+  test_ItemArrayUtils.cpp
   test_ItemValue.cpp
   test_ItemValueUtils.cpp
   test_SubItemValuePerItem.cpp
diff --git a/tests/test_ItemArrayUtils.cpp b/tests/test_ItemArrayUtils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc5611278a166cccdb9225e1eee41de9da6c078a
--- /dev/null
+++ b/tests/test_ItemArrayUtils.cpp
@@ -0,0 +1,770 @@
+#include <catch2/catch_test_macros.hpp>
+#include <catch2/matchers/catch_matchers_all.hpp>
+
+#include <MeshDataBaseForTests.hpp>
+#include <mesh/Connectivity.hpp>
+#include <mesh/ItemArray.hpp>
+#include <mesh/ItemArrayUtils.hpp>
+#include <mesh/Mesh.hpp>
+#include <utils/Messenger.hpp>
+
+// Instantiate to ensure full coverage is performed
+template class ItemArray<int, ItemType::cell>;
+
+// clazy:excludeall=non-pod-global-static
+
+TEST_CASE("ItemArrayUtils", "[mesh]")
+{
+  SECTION("Synchronize")
+  {
+    SECTION("1D")
+    {
+      const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>();
+      const Connectivity<1>& connectivity  = mesh_1d.connectivity();
+
+      SECTION("node")
+      {
+        WeakNodeArray<size_t> weak_node_array{connectivity, 4};
+        auto node_number = connectivity.nodeNumber();
+
+        for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) {
+          SubArray array      = weak_node_array[i_node];
+          const size_t number = node_number[i_node];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        NodeArray<const size_t> node_array{weak_node_array};
+
+        REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto node_owner    = connectivity.nodeOwner();
+          auto node_is_owned = connectivity.nodeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            if (node_is_owned[i_node]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_node_array);
+
+        {   // after synchronization
+          auto node_owner = connectivity.nodeOwner();
+
+          bool is_synchronized = true;
+          for (NodeId i_node = 0; i_node < mesh_1d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("edge")
+      {
+        WeakEdgeArray<size_t> weak_edge_array{connectivity, 4};
+        auto edge_number = connectivity.edgeNumber();
+
+        for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) {
+          SubArray array      = weak_edge_array[i_edge];
+          const size_t number = edge_number[i_edge];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        EdgeArray<const size_t> edge_array{weak_edge_array};
+
+        REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto edge_owner    = connectivity.edgeOwner();
+          auto edge_is_owned = connectivity.edgeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            if (edge_is_owned[i_edge]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_edge_array);
+
+        {   // after synchronization
+          auto edge_owner = connectivity.edgeOwner();
+
+          bool is_synchronized = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_1d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("face")
+      {
+        WeakFaceArray<size_t> weak_face_array{connectivity, 4};
+        auto face_number = connectivity.faceNumber();
+
+        for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) {
+          SubArray array      = weak_face_array[i_face];
+          const size_t number = face_number[i_face];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        FaceArray<const size_t> face_array{weak_face_array};
+
+        REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto face_owner    = connectivity.faceOwner();
+          auto face_is_owned = connectivity.faceIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            if (face_is_owned[i_face]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_face_array);
+
+        {   // after synchronization
+          auto face_owner = connectivity.faceOwner();
+
+          bool is_synchronized = true;
+          for (FaceId i_face = 0; i_face < mesh_1d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("cell")
+      {
+        WeakCellArray<size_t> weak_cell_array{connectivity, 4};
+        auto cell_number = connectivity.cellNumber();
+
+        for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) {
+          SubArray array      = weak_cell_array[i_cell];
+          const size_t number = cell_number[i_cell];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        CellArray<const size_t> cell_array{weak_cell_array};
+
+        REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto cell_owner    = connectivity.cellOwner();
+          auto cell_is_owned = connectivity.cellIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            if (cell_is_owned[i_cell]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_cell_array);
+
+        {   // after synchronization
+          auto cell_owner = connectivity.cellOwner();
+
+          bool is_synchronized = true;
+          for (CellId i_cell = 0; i_cell < mesh_1d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+    }
+
+    SECTION("2D")
+    {
+      const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>();
+      const Connectivity<2>& connectivity  = mesh_2d.connectivity();
+
+      SECTION("node")
+      {
+        WeakNodeArray<size_t> weak_node_array{connectivity, 3};
+        auto node_number = connectivity.nodeNumber();
+
+        for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) {
+          SubArray array      = weak_node_array[i_node];
+          const size_t number = node_number[i_node];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        NodeArray<const size_t> node_array{weak_node_array};
+
+        REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto node_owner    = connectivity.nodeOwner();
+          auto node_is_owned = connectivity.nodeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            if (node_is_owned[i_node]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_node_array);
+
+        {   // after synchronization
+          auto node_owner = connectivity.nodeOwner();
+
+          bool is_synchronized = true;
+          for (NodeId i_node = 0; i_node < mesh_2d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("edge")
+      {
+        WeakEdgeArray<size_t> weak_edge_array{connectivity, 3};
+        auto edge_number = connectivity.edgeNumber();
+
+        for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) {
+          SubArray array      = weak_edge_array[i_edge];
+          const size_t number = edge_number[i_edge];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        EdgeArray<const size_t> edge_array{weak_edge_array};
+
+        REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto edge_owner    = connectivity.edgeOwner();
+          auto edge_is_owned = connectivity.edgeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            if (edge_is_owned[i_edge]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_edge_array);
+
+        {   // after synchronization
+          auto edge_owner = connectivity.edgeOwner();
+
+          bool is_synchronized = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_2d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("face")
+      {
+        WeakFaceArray<size_t> weak_face_array{connectivity, 3};
+        auto face_number = connectivity.faceNumber();
+
+        for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) {
+          SubArray array      = weak_face_array[i_face];
+          const size_t number = face_number[i_face];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        FaceArray<const size_t> face_array{weak_face_array};
+
+        REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto face_owner    = connectivity.faceOwner();
+          auto face_is_owned = connectivity.faceIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            if (face_is_owned[i_face]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_face_array);
+
+        {   // after synchronization
+          auto face_owner = connectivity.faceOwner();
+
+          bool is_synchronized = true;
+          for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("cell")
+      {
+        WeakCellArray<size_t> weak_cell_array{connectivity, 3};
+        auto cell_number = connectivity.cellNumber();
+
+        for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) {
+          SubArray array      = weak_cell_array[i_cell];
+          const size_t number = cell_number[i_cell];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        CellArray<const size_t> cell_array{weak_cell_array};
+
+        REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto cell_owner    = connectivity.cellOwner();
+          auto cell_is_owned = connectivity.cellIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            if (cell_is_owned[i_cell]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_cell_array);
+
+        {   // after synchronization
+          auto cell_owner = connectivity.cellOwner();
+
+          bool is_synchronized = true;
+          for (CellId i_cell = 0; i_cell < mesh_2d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+    }
+
+    SECTION("3D")
+    {
+      const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>();
+      const Connectivity<3>& connectivity  = mesh_3d.connectivity();
+
+      SECTION("node")
+      {
+        WeakNodeArray<size_t> weak_node_array{connectivity, 4};
+        auto node_number = connectivity.nodeNumber();
+
+        for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) {
+          SubArray array      = weak_node_array[i_node];
+          const size_t number = node_number[i_node];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        NodeArray<const size_t> node_array{weak_node_array};
+
+        REQUIRE(node_array.connectivity_ptr() == weak_node_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto node_owner    = connectivity.nodeOwner();
+          auto node_is_owned = connectivity.nodeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            if (node_is_owned[i_node]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_node_array);
+
+        {   // after synchronization
+          auto node_owner = connectivity.nodeOwner();
+
+          bool is_synchronized = true;
+          for (NodeId i_node = 0; i_node < mesh_3d.numberOfNodes(); ++i_node) {
+            SubArray array      = node_array[i_node];
+            const size_t number = node_number[i_node];
+            const size_t owner  = node_owner[i_node];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("edge")
+      {
+        WeakEdgeArray<size_t> weak_edge_array{connectivity, 4};
+        auto edge_number = connectivity.edgeNumber();
+
+        for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) {
+          SubArray array      = weak_edge_array[i_edge];
+          const size_t number = edge_number[i_edge];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        EdgeArray<const size_t> edge_array{weak_edge_array};
+
+        REQUIRE(edge_array.connectivity_ptr() == weak_edge_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto edge_owner    = connectivity.edgeOwner();
+          auto edge_is_owned = connectivity.edgeIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            if (edge_is_owned[i_edge]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_edge_array);
+
+        {   // after synchronization
+          auto edge_owner = connectivity.edgeOwner();
+
+          bool is_synchronized = true;
+          for (EdgeId i_edge = 0; i_edge < mesh_3d.numberOfEdges(); ++i_edge) {
+            SubArray array      = edge_array[i_edge];
+            const size_t number = edge_number[i_edge];
+            const size_t owner  = edge_owner[i_edge];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("face")
+      {
+        WeakFaceArray<size_t> weak_face_array{connectivity, 4};
+        auto face_number = connectivity.faceNumber();
+
+        for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) {
+          SubArray array      = weak_face_array[i_face];
+          const size_t number = face_number[i_face];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        FaceArray<const size_t> face_array{weak_face_array};
+
+        REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto face_owner    = connectivity.faceOwner();
+          auto face_is_owned = connectivity.faceIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            if (face_is_owned[i_face]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_face_array);
+
+        {   // after synchronization
+          auto face_owner = connectivity.faceOwner();
+
+          bool is_synchronized = true;
+          for (FaceId i_face = 0; i_face < mesh_3d.numberOfFaces(); ++i_face) {
+            SubArray array      = face_array[i_face];
+            const size_t number = face_number[i_face];
+            const size_t owner  = face_owner[i_face];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+
+      SECTION("cell")
+      {
+        WeakCellArray<size_t> weak_cell_array{connectivity, 4};
+        auto cell_number = connectivity.cellNumber();
+
+        for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) {
+          SubArray array      = weak_cell_array[i_cell];
+          const size_t number = cell_number[i_cell];
+          for (size_t i = 0; i < array.size(); ++i) {
+            array[i] = number + (parallel::rank() + 1) * i;
+          }
+        }
+
+        CellArray<const size_t> cell_array{weak_cell_array};
+
+        REQUIRE(cell_array.connectivity_ptr() == weak_cell_array.connectivity_ptr());
+
+        {   // before synchronization
+          auto cell_owner    = connectivity.cellOwner();
+          auto cell_is_owned = connectivity.cellIsOwned();
+
+          bool is_synchronized = (parallel::size() > 1);
+          bool is_valid        = true;
+          for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            if (cell_is_owned[i_cell]) {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_valid &= (array[i] == number + (owner + 1) * i);
+              }
+            } else {
+              for (size_t i = 0; i < array.size(); ++i) {
+                is_synchronized &= (array[i] == number + (owner + 1) * i);
+              }
+            }
+          }
+
+          REQUIRE(is_valid);
+          REQUIRE(not is_synchronized);
+        }
+
+        synchronize(weak_cell_array);
+
+        {   // after synchronization
+          auto cell_owner = connectivity.cellOwner();
+
+          bool is_synchronized = true;
+          for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) {
+            SubArray array      = cell_array[i_cell];
+            const size_t number = cell_number[i_cell];
+            const size_t owner  = cell_owner[i_cell];
+            for (size_t i = 0; i < array.size(); ++i) {
+              is_synchronized &= (array[i] == number + (owner + 1) * i);
+            }
+          }
+
+          REQUIRE(is_synchronized);
+        }
+      }
+    }
+  }
+}