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); + } + } + } + } +}