diff --git a/src/mesh/IConnectivity.hpp b/src/mesh/IConnectivity.hpp index 9bfb8e5043088a18880440235cd72b1677c1f519..90c49e4d818e6caa6414992e9ebaf7bdf46f15cc 100644 --- a/src/mesh/IConnectivity.hpp +++ b/src/mesh/IConnectivity.hpp @@ -13,6 +13,9 @@ class IConnectivity : public std::enable_shared_from_this<IConnectivity> template <typename DataType, typename ItemOfItem, typename ConnectivityPtr> friend class SubItemValuePerItem; + template <typename DataType, typename ItemOfItem, typename ConnectivityPtr> + friend class SubItemArrayPerItem; + virtual const ConnectivityMatrix& _getMatrix(const ItemType& item_type_0, const ItemType& item_type_1) const = 0; public: diff --git a/src/mesh/SubItemArrayPerItem.hpp b/src/mesh/SubItemArrayPerItem.hpp new file mode 100644 index 0000000000000000000000000000000000000000..431c3f4bee962857ff0b361c56a9ab5e987fde35 --- /dev/null +++ b/src/mesh/SubItemArrayPerItem.hpp @@ -0,0 +1,361 @@ +#ifndef SUBITEM_ARRAY_PER_ITEM_HPP +#define SUBITEM_ARRAY_PER_ITEM_HPP + +#include <mesh/ConnectivityMatrix.hpp> +#include <mesh/IConnectivity.hpp> +#include <mesh/ItemId.hpp> +#include <mesh/ItemOfItemType.hpp> +#include <mesh/ItemType.hpp> +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/SubArray.hpp> + +#include <memory> + +template <typename DataType, typename ItemOfItem, typename ConnectivityPtr = std::shared_ptr<const IConnectivity>> +class SubItemArrayPerItem +{ + public: + static constexpr ItemType item_type{ItemOfItem::item_type}; + static constexpr ItemType sub_item_type{ItemOfItem::sub_item_type}; + + using ItemOfItemType = ItemOfItem; + using data_type = DataType; + using ItemId = ItemIdT<item_type>; + using index_type = ItemId; + + private: + using ConnectivitySharedPtr = std::shared_ptr<const IConnectivity>; + using ConnectivityWeakPtr = std::weak_ptr<const IConnectivity>; + + static_assert(std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr> or + std::is_same_v<ConnectivityPtr, ConnectivityWeakPtr>); + + ConnectivityPtr m_connectivity_ptr; + + typename ConnectivityMatrix::HostRowType m_host_row_map; + Array<DataType> m_arrays_values; + + size_t m_size_of_arrays; + + // Allow const std:shared_ptr version to access our data + friend SubItemArrayPerItem<std::add_const_t<DataType>, ItemOfItem, ConnectivitySharedPtr>; + + // Allow const std:weak_ptr version to access our data + friend SubItemArrayPerItem<std::add_const_t<DataType>, ItemOfItem, ConnectivityWeakPtr>; + + // Allow const std:shared_ptr version to access our data + friend SubItemArrayPerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivitySharedPtr>; + + // Allow const std:weak_ptr version to access our data + friend SubItemArrayPerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivityWeakPtr>; + + public: + using ToShared = SubItemArrayPerItem<DataType, ItemOfItem, ConnectivitySharedPtr>; + + class SubView + { + public: + using data_type = DataType; + + private: + PUGS_RESTRICT DataType* const m_sub_arrays; + const size_t m_size; + const size_t m_size_of_arrays; + + public: + template <typename IndexType> + PUGS_FORCEINLINE SubArray<DataType> + operator[](IndexType i) const noexcept(NO_ASSERT) + { + static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral arrays"); + Assert(static_cast<size_t>(i) < m_size); + return SubArray<DataType>(m_sub_arrays, i * m_size_of_arrays, m_size_of_arrays); + } + + template <typename IndexType> + PUGS_FORCEINLINE SubArray<DataType> + operator[](IndexType i) noexcept(NO_ASSERT) + { + static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral arrays"); + Assert(static_cast<size_t>(i) < m_size); + return SubArray<DataType>(m_sub_arrays, i * m_size_of_arrays, m_size_of_arrays); + } + + PUGS_INLINE + size_t + size() const noexcept + { + return m_size; + } + + SubView(const SubView&) = delete; + + PUGS_INLINE + SubView(SubView&&) noexcept = delete; + + PUGS_INLINE + SubView(const Array<DataType>& arrays, size_t begin, size_t end, size_t size_of_arrays) noexcept(NO_ASSERT) + : m_sub_arrays{&(arrays[begin * size_of_arrays])}, m_size{end - begin}, m_size_of_arrays{size_of_arrays} + { + Assert(begin <= end); + Assert(end <= arrays.size()); + } + }; + + friend PUGS_INLINE SubItemArrayPerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivityPtr> + copy(SubItemArrayPerItem<DataType, ItemOfItem, ConnectivityPtr>& source) + { + SubItemArrayPerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivityPtr> image; + + image.m_connectivity_ptr = source.m_connectivity_ptr; + image.m_host_row_map = source.m_host_row_map; + image.m_arrays_values = copy(source.m_arrays_values); + image.m_size_of_arrays = source.m_size_of_arrays; + return image; + } + + PUGS_INLINE + bool + isBuilt() const noexcept + { + return m_connectivity_ptr.use_count() != 0; + } + + PUGS_INLINE + std::shared_ptr<const IConnectivity> + connectivity_ptr() const noexcept + { + if constexpr (std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr>) { + return m_connectivity_ptr; + } else { + return m_connectivity_ptr.lock(); + } + } + + template <typename IndexType, typename SubIndexType> + PUGS_FORCEINLINE SubArray<DataType> + operator()(IndexType item_id, SubIndexType i) const noexcept(NO_ASSERT) + { + static_assert(std::is_same_v<IndexType, ItemId>, "first index must be of the correct ItemId type"); + static_assert(std::is_integral_v<SubIndexType>, "second index must be an integral type"); + Assert(this->isBuilt()); + Assert(i + m_host_row_map(size_t{item_id}) < m_host_row_map(size_t{item_id} + 1)); + return SubArray(m_arrays_values, (m_host_row_map(size_t{item_id}) + i) * m_size_of_arrays, m_size_of_arrays); + } + + // Following Kokkos logic, these classes are view and const view does allow + // changes in data + template <typename ArrayIndexType> + DataType& + operator[](const ArrayIndexType& i) const noexcept(NO_ASSERT) + { + static_assert(std::is_integral_v<ArrayIndexType>, "index must be an integral type"); + Assert(this->isBuilt()); + Assert(static_cast<size_t>(i) < m_arrays_values.size()); + return m_arrays_values[i]; + } + + PUGS_INLINE + size_t + numberOfValues() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return m_arrays_values.size(); + } + + PUGS_INLINE + size_t + numberOfItems() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + Assert(m_host_row_map.extent(0) > 0); + return m_host_row_map.extent(0) - 1; + } + + PUGS_INLINE size_t + sizeOfArrays() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return m_size_of_arrays; + } + + template <typename IndexType> + PUGS_INLINE size_t + numberOfSubArrays(IndexType item_id) const noexcept(NO_ASSERT) + { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); + Assert(this->isBuilt()); + Assert(item_id < this->numberOfItems()); + return m_host_row_map(size_t{item_id} + 1) - m_host_row_map(size_t{item_id}); + } + + template <typename IndexType> + PUGS_INLINE SubView + itemArrays(IndexType item_id) noexcept(NO_ASSERT) + { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); + Assert(this->isBuilt()); + Assert(item_id < this->numberOfItems()); + const auto& item_begin = m_host_row_map(size_t{item_id}); + const auto& item_end = m_host_row_map(size_t{item_id} + 1); + return SubView(m_arrays_values, item_begin, item_end, m_size_of_arrays); + } + + // Following Kokkos logic, these classes are view and const view does allow + // changes in data + template <typename IndexType> + PUGS_INLINE SubView + itemArrays(IndexType item_id) const noexcept(NO_ASSERT) + { + static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); + Assert(this->isBuilt()); + Assert(item_id < this->numberOfItems()); + const auto& item_begin = m_host_row_map(size_t{item_id}); + const auto& item_end = m_host_row_map(size_t{item_id} + 1); + return SubView(m_arrays_values, item_begin, item_end, m_size_of_arrays); + } + + template <typename DataType2, typename ConnectivityPtr2> + PUGS_INLINE SubItemArrayPerItem& + operator=(const SubItemArrayPerItem<DataType2, ItemOfItem, ConnectivityPtr2>& sub_item_array_per_item) noexcept + { + // ensures that DataType is the same as source DataType2 + static_assert(std::is_same_v<std::remove_const_t<DataType>, std::remove_const_t<DataType2>>, + "Cannot assign SubItemArrayPerItem of different type"); + // ensures that const is not lost through copy + static_assert(((std::is_const_v<DataType2> and std::is_const_v<DataType>) or not std::is_const_v<DataType2>), + "Cannot assign SubItemArrayPerItem of const data to " + "SubItemArrayPerItem of non-const data"); + m_host_row_map = sub_item_array_per_item.m_host_row_map; + m_arrays_values = sub_item_array_per_item.m_arrays_values; + m_size_of_arrays = sub_item_array_per_item.m_size_of_arrays; + + if constexpr (std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr> and + std::is_same_v<ConnectivityPtr2, ConnectivityWeakPtr>) { + m_connectivity_ptr = sub_item_array_per_item.m_connectivity_ptr.lock(); + } else { + m_connectivity_ptr = sub_item_array_per_item.m_connectivity_ptr; + } + + return *this; + } + + template <typename DataType2, typename ConnectivityPtr2> + PUGS_INLINE + SubItemArrayPerItem( + const SubItemArrayPerItem<DataType2, ItemOfItem, ConnectivityPtr2>& sub_item_array_per_item) noexcept + { + this->operator=(sub_item_array_per_item); + } + + SubItemArrayPerItem() = default; + + SubItemArrayPerItem(const IConnectivity& connectivity, size_t size_of_array) noexcept + : m_connectivity_ptr{connectivity.shared_ptr()}, m_size_of_arrays(size_of_array) + { + static_assert(not std::is_const_v<DataType>, "Cannot allocate SubItemArrayPerItem of const data: only " + "view is supported"); + + ConnectivityMatrix connectivity_matrix = connectivity._getMatrix(item_type, sub_item_type); + + m_host_row_map = connectivity_matrix.rowsMap(); + m_arrays_values = Array<std::remove_const_t<DataType>>(connectivity_matrix.numEntries() * m_size_of_arrays); + } + + ~SubItemArrayPerItem() = default; +}; + +// Item arrays at nodes + +template <typename DataType> +using NodeArrayPerEdge = SubItemArrayPerItem<DataType, NodeOfEdge>; + +template <typename DataType> +using NodeArrayPerFace = SubItemArrayPerItem<DataType, NodeOfFace>; + +template <typename DataType> +using NodeArrayPerCell = SubItemArrayPerItem<DataType, NodeOfCell>; + +// Item arrays at edges + +template <typename DataType> +using EdgeArrayPerNode = SubItemArrayPerItem<DataType, EdgeOfNode>; + +template <typename DataType> +using EdgeArrayPerFace = SubItemArrayPerItem<DataType, EdgeOfFace>; + +template <typename DataType> +using EdgeArrayPerCell = SubItemArrayPerItem<DataType, EdgeOfCell>; + +// Item arrays at faces + +template <typename DataType> +using FaceArrayPerNode = SubItemArrayPerItem<DataType, FaceOfNode>; + +template <typename DataType> +using FaceArrayPerEdge = SubItemArrayPerItem<DataType, FaceOfEdge>; + +template <typename DataType> +using FaceArrayPerCell = SubItemArrayPerItem<DataType, FaceOfCell>; + +// Item arrays at cells + +template <typename DataType> +using CellArrayPerNode = SubItemArrayPerItem<DataType, CellOfNode>; + +template <typename DataType> +using CellArrayPerEdge = SubItemArrayPerItem<DataType, CellOfEdge>; + +template <typename DataType> +using CellArrayPerFace = SubItemArrayPerItem<DataType, CellOfFace>; + +// Weak versions: should not be used outside of Connectivity +// Item arrays at nodes + +template <typename DataType, typename ItemOfItem> +using WeakSubItemArrayPerItem = SubItemArrayPerItem<DataType, ItemOfItem, std::weak_ptr<const IConnectivity>>; + +template <typename DataType> +using WeakNodeArrayPerEdge = WeakSubItemArrayPerItem<DataType, NodeOfEdge>; + +template <typename DataType> +using WeakNodeArrayPerFace = WeakSubItemArrayPerItem<DataType, NodeOfFace>; + +template <typename DataType> +using WeakNodeArrayPerCell = WeakSubItemArrayPerItem<DataType, NodeOfCell>; + +// Item arrays at edges + +template <typename DataType> +using WeakEdgeArrayPerNode = WeakSubItemArrayPerItem<DataType, EdgeOfNode>; + +template <typename DataType> +using WeakEdgeArrayPerFace = WeakSubItemArrayPerItem<DataType, EdgeOfFace>; + +template <typename DataType> +using WeakEdgeArrayPerCell = WeakSubItemArrayPerItem<DataType, EdgeOfCell>; + +// Item arrays at faces + +template <typename DataType> +using WeakFaceArrayPerNode = WeakSubItemArrayPerItem<DataType, FaceOfNode>; + +template <typename DataType> +using WeakFaceArrayPerEdge = WeakSubItemArrayPerItem<DataType, FaceOfEdge>; + +template <typename DataType> +using WeakFaceArrayPerCell = WeakSubItemArrayPerItem<DataType, FaceOfCell>; + +// Item arrays at cells + +template <typename DataType> +using WeakCellArrayPerNode = WeakSubItemArrayPerItem<DataType, CellOfNode>; + +template <typename DataType> +using WeakCellArrayPerEdge = WeakSubItemArrayPerItem<DataType, CellOfEdge>; + +template <typename DataType> +using WeakCellArrayPerFace = WeakSubItemArrayPerItem<DataType, CellOfFace>; + +#endif // SUBITEM_ARRAY_PER_ITEM_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6f255448f4cdf002bc0d0df0a795bbca26935efe..c99154ff0dee78cf7aadf95c70cccfbeb36ffa75 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -105,6 +105,7 @@ add_executable (mpi_unit_tests test_ItemValue.cpp test_ItemValueUtils.cpp test_SubItemValuePerItem.cpp + test_SubItemArrayPerItem.cpp ) add_library(test_Pugs_MeshDataBase diff --git a/tests/test_SubItemArrayPerItem.cpp b/tests/test_SubItemArrayPerItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5438398b0c1d5ba0559214473f41d13dba3cb8b4 --- /dev/null +++ b/tests/test_SubItemArrayPerItem.cpp @@ -0,0 +1,869 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/Mesh.hpp> +#include <mesh/SubItemArrayPerItem.hpp> +#include <utils/Messenger.hpp> + +// Instantiate to ensure full coverage is performed +template class SubItemArrayPerItem<size_t, NodeOfCell>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SubItemArrayPerItem", "[mesh]") +{ + SECTION("default constructors") + { + REQUIRE_NOTHROW(NodeArrayPerEdge<int>{}); + REQUIRE_NOTHROW(NodeArrayPerFace<int>{}); + REQUIRE_NOTHROW(NodeArrayPerCell<int>{}); + + REQUIRE_NOTHROW(EdgeArrayPerNode<int>{}); + REQUIRE_NOTHROW(EdgeArrayPerFace<int>{}); + REQUIRE_NOTHROW(EdgeArrayPerCell<int>{}); + + REQUIRE_NOTHROW(FaceArrayPerNode<int>{}); + REQUIRE_NOTHROW(FaceArrayPerEdge<int>{}); + REQUIRE_NOTHROW(FaceArrayPerCell<int>{}); + + REQUIRE_NOTHROW(CellArrayPerNode<int>{}); + REQUIRE_NOTHROW(CellArrayPerEdge<int>{}); + REQUIRE_NOTHROW(CellArrayPerFace<int>{}); + + REQUIRE(not NodeArrayPerEdge<int>{}.isBuilt()); + REQUIRE(not NodeArrayPerFace<int>{}.isBuilt()); + REQUIRE(not NodeArrayPerCell<int>{}.isBuilt()); + + REQUIRE(not EdgeArrayPerNode<int>{}.isBuilt()); + REQUIRE(not EdgeArrayPerFace<int>{}.isBuilt()); + REQUIRE(not EdgeArrayPerCell<int>{}.isBuilt()); + + REQUIRE(not FaceArrayPerNode<int>{}.isBuilt()); + REQUIRE(not FaceArrayPerEdge<int>{}.isBuilt()); + REQUIRE(not FaceArrayPerCell<int>{}.isBuilt()); + + REQUIRE(not CellArrayPerNode<int>{}.isBuilt()); + REQUIRE(not CellArrayPerEdge<int>{}.isBuilt()); + REQUIRE(not CellArrayPerFace<int>{}.isBuilt()); + } + + SECTION("dimensions") + { + auto number_of_values = [](const auto& sub_item_array_per_item) -> size_t { + using SubItemArrayPerItemType = std::decay_t<decltype(sub_item_array_per_item)>; + using ItemId = typename SubItemArrayPerItemType::ItemId; + + size_t number = 0; + for (ItemId item_id = 0; item_id < sub_item_array_per_item.numberOfItems(); ++item_id) { + for (size_t i = 0; i < sub_item_array_per_item.numberOfSubArrays(item_id); ++i) { + number += sub_item_array_per_item(item_id, i).size(); + } + } + return number; + }; + + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfValues() == number_of_values(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= + (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)) and + (node_array_per_cell.itemArrays(cell_id).size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + const NodeArrayPerCell<const int> const_node_array_per_cell = node_array_per_cell; + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= + (const_node_array_per_cell.itemArrays(cell_id).size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfValues() == number_of_values(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerCell<int> face_array_per_cell{connectivity, 2}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfValues() == number_of_values(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 2); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 2}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfValues() == number_of_values(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 2); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfValues() == number_of_values(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + CellArrayPerNode<int> cell_array_per_node{connectivity, 4}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfValues() == number_of_values(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 4); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + } + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 5}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfValues() == number_of_values(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 5); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfValues() == number_of_values(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfValues() == number_of_values(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfValues() == number_of_values(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 3); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + + NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; + REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_array_per_face.numberOfValues() == number_of_values(node_array_per_face)); + REQUIRE(node_array_per_face.sizeOfArrays() == 2); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfValues() == number_of_values(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 5}; + REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_array_per_edge.numberOfValues() == number_of_values(node_array_per_edge)); + REQUIRE(node_array_per_edge.sizeOfArrays() == 5); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeArrayPerNode<int> edge_array_per_node{connectivity, 4}; + REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_array_per_node.numberOfValues() == number_of_values(edge_array_per_node)); + REQUIRE(edge_array_per_node.sizeOfArrays() == 4); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerNode<int> face_array_per_node{connectivity, 3}; + REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_array_per_node.numberOfValues() == number_of_values(face_array_per_node)); + REQUIRE(face_array_per_node.sizeOfArrays() == 3); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + + CellArrayPerNode<int> cell_array_per_node{connectivity, 2}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfValues() == number_of_values(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 2); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + } + } + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + SECTION("per cell") + { + NodeArrayPerCell<int> node_array_per_cell{connectivity, 3}; + REQUIRE(node_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_array_per_cell.numberOfValues() == number_of_values(node_array_per_cell)); + REQUIRE(node_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_node_matrix = connectivity.cellToNodeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_node_matrix[cell_id].size() == node_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 4}; + REQUIRE(edge_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_array_per_cell.numberOfValues() == number_of_values(edge_array_per_cell)); + REQUIRE(edge_array_per_cell.sizeOfArrays() == 4); + + auto cell_to_edge_matrix = connectivity.cellToEdgeMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_edge_matrix[cell_id].size() == edge_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerCell<int> face_array_per_cell{connectivity, 3}; + REQUIRE(face_array_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_array_per_cell.numberOfValues() == number_of_values(face_array_per_cell)); + REQUIRE(face_array_per_cell.sizeOfArrays() == 3); + + auto cell_to_face_matrix = connectivity.cellToFaceMatrix(); + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= (cell_to_face_matrix[cell_id].size() == face_array_per_cell.numberOfSubArrays(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellArrayPerFace<int> cell_array_per_face{connectivity, 5}; + REQUIRE(cell_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_array_per_face.numberOfValues() == number_of_values(cell_array_per_face)); + REQUIRE(cell_array_per_face.sizeOfArrays() == 5); + + auto face_to_cell_matrix = connectivity.faceToCellMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_cell_matrix[face_id].size() == cell_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + + EdgeArrayPerFace<int> edge_array_per_face{connectivity, 3}; + REQUIRE(edge_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(edge_array_per_face.numberOfValues() == number_of_values(edge_array_per_face)); + REQUIRE(edge_array_per_face.sizeOfArrays() == 3); + + auto face_to_edge_matrix = connectivity.faceToEdgeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_edge_matrix[face_id].size() == edge_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + + NodeArrayPerFace<int> node_array_per_face{connectivity, 2}; + REQUIRE(node_array_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_array_per_face.numberOfValues() == number_of_values(node_array_per_face)); + REQUIRE(node_array_per_face.sizeOfArrays() == 2); + + auto face_to_node_matrix = connectivity.faceToNodeMatrix(); + { + bool is_correct = true; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + is_correct &= (face_to_node_matrix[face_id].size() == node_array_per_face.numberOfSubArrays(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellArrayPerEdge<int> cell_array_per_edge{connectivity, 3}; + REQUIRE(cell_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_array_per_edge.numberOfValues() == number_of_values(cell_array_per_edge)); + REQUIRE(cell_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_cell_matrix = connectivity.edgeToCellMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_cell_matrix[edge_id].size() == cell_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerEdge<int> face_array_per_edge{connectivity, 5}; + REQUIRE(face_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(face_array_per_edge.numberOfValues() == number_of_values(face_array_per_edge)); + REQUIRE(face_array_per_edge.sizeOfArrays() == 5); + + auto edge_to_face_matrix = connectivity.edgeToFaceMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_face_matrix[edge_id].size() == face_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; + REQUIRE(node_array_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_array_per_edge.numberOfValues() == number_of_values(node_array_per_edge)); + REQUIRE(node_array_per_edge.sizeOfArrays() == 3); + + auto edge_to_node_matrix = connectivity.edgeToNodeMatrix(); + { + bool is_correct = true; + for (EdgeId edge_id = 0; edge_id < connectivity.numberOfEdges(); ++edge_id) { + is_correct &= (edge_to_node_matrix[edge_id].size() == node_array_per_edge.numberOfSubArrays(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeArrayPerNode<int> edge_array_per_node{connectivity, 3}; + REQUIRE(edge_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_array_per_node.numberOfValues() == number_of_values(edge_array_per_node)); + REQUIRE(edge_array_per_node.sizeOfArrays() == 3); + + auto node_to_edge_matrix = connectivity.nodeToEdgeMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_edge_matrix[node_id].size() == edge_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + + FaceArrayPerNode<int> face_array_per_node{connectivity, 4}; + REQUIRE(face_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_array_per_node.numberOfValues() == number_of_values(face_array_per_node)); + REQUIRE(face_array_per_node.sizeOfArrays() == 4); + + auto node_to_face_matrix = connectivity.nodeToFaceMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_face_matrix[node_id].size() == face_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + + CellArrayPerNode<int> cell_array_per_node{connectivity, 5}; + REQUIRE(cell_array_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_array_per_node.numberOfValues() == number_of_values(cell_array_per_node)); + REQUIRE(cell_array_per_node.sizeOfArrays() == 5); + + auto node_to_cell_matrix = connectivity.nodeToCellMatrix(); + { + bool is_correct = true; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + is_correct &= (node_to_cell_matrix[node_id].size() == cell_array_per_node.numberOfSubArrays(node_id)); + } + REQUIRE(is_correct); + } + } + } + } + + SECTION("array view") + { + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + EdgeArrayPerCell<size_t> edge_arrays_per_cell{connectivity, 3}; + { + size_t array = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { + for (size_t i = 0; i < edge_arrays_per_cell(cell_id, i_edge).size(); ++i) { + edge_arrays_per_cell(cell_id, i_edge)[i] = array++; + } + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < edge_arrays_per_cell.numberOfValues(); ++i) { + is_same &= (edge_arrays_per_cell[i] == i); + } + REQUIRE(is_same); + } + + for (size_t i = 0; i < edge_arrays_per_cell.numberOfValues(); ++i) { + edge_arrays_per_cell[i] = i * i + 1; + } + { + bool is_same = true; + size_t i = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_arrays_per_cell.numberOfSubArrays(cell_id); ++i_edge) { + for (size_t l = 0; l < edge_arrays_per_cell(cell_id, i_edge).size(); ++l, ++i) { + is_same &= (edge_arrays_per_cell(cell_id, i_edge)[l] == i * i + 1); + } + } + } + REQUIRE(is_same); + } + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + CellArrayPerFace<size_t> cell_arrays_per_face{connectivity, 3}; + { + size_t array = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { + for (size_t i = 0; i < cell_arrays_per_face(face_id, i_cell).size(); ++i) { + cell_arrays_per_face(face_id, i_cell)[i] = array++; + } + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < cell_arrays_per_face.numberOfValues(); ++i) { + is_same &= (cell_arrays_per_face[i] == i); + } + REQUIRE(is_same); + } + for (size_t i = 0; i < cell_arrays_per_face.numberOfValues(); ++i) { + cell_arrays_per_face[i] = 3 * i + 1; + } + { + bool is_same = true; + size_t i = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_arrays_per_face.numberOfSubArrays(face_id); ++i_cell) { + for (size_t l = 0; l < cell_arrays_per_face(face_id, i_cell).size(); ++l, ++i) { + is_same &= (cell_arrays_per_face(face_id, i_cell)[l] == 3 * i + 1); + } + } + } + REQUIRE(is_same); + } + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + FaceArrayPerNode<size_t> face_arrays_per_node{connectivity, 3}; + { + size_t array = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { + for (size_t i = 0; i < face_arrays_per_node(node_id, i_face).size(); ++i) + face_arrays_per_node(node_id, i_face)[i] = array++; + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < face_arrays_per_node.numberOfValues(); ++i) { + is_same &= (face_arrays_per_node[i] == i); + } + REQUIRE(is_same); + } + + for (size_t i = 0; i < face_arrays_per_node.numberOfValues(); ++i) { + face_arrays_per_node[i] = 3 + i * i; + } + { + bool is_same = true; + size_t i = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_arrays_per_node.numberOfSubArrays(node_id); ++i_face) { + for (size_t l = 0; l < face_arrays_per_node(node_id, i_face).size(); ++l, ++i) { + is_same &= (face_arrays_per_node(node_id, i_face)[l] == 3 + i * i); + } + } + } + REQUIRE(is_same); + } + } + } + + SECTION("copy") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + SECTION("classic") + { + NodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; + for (size_t i = 0; i < node_array_per_cell.numberOfValues(); ++i) { + node_array_per_cell[i] = i; + } + + NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_array_per_cell[i] == node_array_per_cell[i]); + } + + REQUIRE(is_same); + } + + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + auto node_array_list = node_array_per_cell.itemArrays(cell_id); + for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { + auto node_array = node_array_list[i_node]; + for (size_t i = 0; i < node_array.size(); ++i) { + node_array[i] = cell_id + i_node + i; + } + } + } + } + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_array_per_cell[i] == node_array_per_cell[i]); + } + + REQUIRE(not is_same); + } + } + + SECTION("from weak") + { + WeakNodeArrayPerCell<size_t> node_array_per_cell{connectivity, 3}; + for (size_t i = 0; i < node_array_per_cell.numberOfValues(); ++i) { + node_array_per_cell[i] = i; + } + + NodeArrayPerCell<size_t> copy_node_array_per_cell = copy(node_array_per_cell); + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_array_per_cell[i] == node_array_per_cell[i]); + } + + REQUIRE(is_same); + } + + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + auto node_array_list = node_array_per_cell.itemArrays(cell_id); + for (size_t i_node = 0; i_node < node_array_per_cell.numberOfSubArrays(cell_id); ++i_node) { + auto node_array = node_array_list[i_node]; + for (size_t i = 0; i < node_array.size(); ++i) { + node_array[i] = cell_id + i_node + i; + } + } + } + } + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_array_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_array_per_cell[i] == node_array_per_cell[i]); + } + + REQUIRE(not is_same); + } + } + } + + SECTION("WeakSubItemArrayPerItem") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + WeakFaceArrayPerCell<int> weak_face_array_per_cell{connectivity, 3}; + + for (size_t i = 0; i < weak_face_array_per_cell.numberOfValues(); ++i) { + weak_face_array_per_cell[i] = i; + } + + FaceArrayPerCell<const int> face_array_per_cell{weak_face_array_per_cell}; + + REQUIRE(face_array_per_cell.connectivity_ptr() == weak_face_array_per_cell.connectivity_ptr()); + REQUIRE(face_array_per_cell.sizeOfArrays() == weak_face_array_per_cell.sizeOfArrays()); + + bool is_same = true; + for (size_t i = 0; i < weak_face_array_per_cell.numberOfValues(); ++i) { + is_same &= (face_array_per_cell[i] == weak_face_array_per_cell[i]); + } + REQUIRE(is_same); + } + +#ifndef NDEBUG + SECTION("error") + { + SECTION("checking for build SubItemArrayPerItem") + { + CellArrayPerNode<int> cell_array_per_node; + REQUIRE_THROWS_AS(cell_array_per_node[0], AssertError); + REQUIRE_THROWS_AS(cell_array_per_node.itemArrays(NodeId{0}), AssertError); + REQUIRE_THROWS_AS(cell_array_per_node(NodeId{0}, 0), AssertError); + REQUIRE_THROWS_AS(cell_array_per_node.sizeOfArrays(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_node.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_node.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_node.numberOfSubArrays(NodeId{0}), AssertError); + + FaceArrayPerCell<int> face_array_per_cell; + REQUIRE_THROWS_AS(face_array_per_cell[0], AssertError); + REQUIRE_THROWS_AS(face_array_per_cell.itemArrays(CellId{0}), AssertError); + REQUIRE_THROWS_AS(face_array_per_cell(CellId{0}, 0), AssertError); + REQUIRE_THROWS_AS(face_array_per_cell.sizeOfArrays(), AssertError); + REQUIRE_THROWS_AS(face_array_per_cell.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(face_array_per_cell.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(face_array_per_cell.numberOfSubArrays(CellId{0}), AssertError); + + CellArrayPerEdge<int> cell_array_per_edge; + REQUIRE_THROWS_AS(cell_array_per_edge[0], AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge.itemArrays(EdgeId{0}), AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge(EdgeId{0}, 0), AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge.sizeOfArrays(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(cell_array_per_edge.numberOfSubArrays(EdgeId{0}), AssertError); + + NodeArrayPerFace<int> node_array_per_face; + REQUIRE_THROWS_AS(node_array_per_face[0], AssertError); + REQUIRE_THROWS_AS(node_array_per_face.itemArrays(FaceId{0}), AssertError); + REQUIRE_THROWS_AS(node_array_per_face(FaceId{0}, 0), AssertError); + REQUIRE_THROWS_AS(node_array_per_face.sizeOfArrays(), AssertError); + REQUIRE_THROWS_AS(node_array_per_face.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(node_array_per_face.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(node_array_per_face.numberOfSubArrays(FaceId{0}), AssertError); + } + + SECTION("checking for bounds violation") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellArrayPerFace<int> cell_array_per_face{connectivity, 3}; + { + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(cell_array_per_face(invalid_face_id, 0), AssertError); + } + if (connectivity.numberOfFaces() > 0) { + FaceId face_id = 0; + const auto& cell_arrays = cell_array_per_face.itemArrays(face_id); + REQUIRE_THROWS_AS(cell_array_per_face(face_id, cell_arrays.size()), AssertError); + REQUIRE_THROWS_AS(cell_arrays[cell_arrays.size()], AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemArrays(face_id)[cell_arrays.size()], AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemArrays(face_id)[0][cell_array_per_face.sizeOfArrays()], AssertError); + REQUIRE_THROWS_AS(cell_array_per_face.itemArrays(face_id)[0][cell_array_per_face.sizeOfArrays()] = 2, + AssertError); + } + + FaceArrayPerNode<int> face_array_per_node{connectivity, 5}; + { + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(face_array_per_node(invalid_node_id, 0), AssertError); + } + if (connectivity.numberOfNodes() > 0) { + NodeId node_id = 0; + const auto& face_arrays = face_array_per_node.itemArrays(node_id); + REQUIRE_THROWS_AS(face_array_per_node(node_id, face_arrays.size()), AssertError); + REQUIRE_THROWS_AS(face_arrays[face_arrays.size()], AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemArrays(node_id)[face_arrays.size()], AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemArrays(node_id)[0][face_array_per_node.sizeOfArrays()], AssertError); + REQUIRE_THROWS_AS(face_array_per_node.itemArrays(node_id)[0][face_array_per_node.sizeOfArrays()] = 2, + AssertError); + } + + EdgeArrayPerCell<int> edge_array_per_cell{connectivity, 3}; + { + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(edge_array_per_cell(invalid_cell_id, 0), AssertError); + } + if (connectivity.numberOfCells() > 0) { + CellId cell_id = 0; + const auto& edge_arrays = edge_array_per_cell.itemArrays(cell_id); + REQUIRE_THROWS_AS(edge_array_per_cell(cell_id, edge_arrays.size()), AssertError); + REQUIRE_THROWS_AS(edge_arrays[edge_arrays.size()], AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemArrays(cell_id)[edge_arrays.size()], AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemArrays(cell_id)[0][edge_array_per_cell.sizeOfArrays()], AssertError); + REQUIRE_THROWS_AS(edge_array_per_cell.itemArrays(cell_id)[0][edge_array_per_cell.sizeOfArrays()] == 2, + AssertError); + } + + NodeArrayPerEdge<int> node_array_per_edge{connectivity, 3}; + { + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(node_array_per_edge(invalid_edge_id, 0), AssertError); + } + if (connectivity.numberOfEdges() > 0) { + EdgeId edge_id = 0; + const auto& node_arrays = node_array_per_edge.itemArrays(edge_id); + REQUIRE_THROWS_AS(node_array_per_edge(edge_id, node_arrays.size()), AssertError); + REQUIRE_THROWS_AS(node_arrays[node_arrays.size()], AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemArrays(edge_id)[node_arrays.size()], AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemArrays(edge_id)[0][node_array_per_edge.sizeOfArrays()], AssertError); + REQUIRE_THROWS_AS(node_array_per_edge.itemArrays(edge_id)[0][node_array_per_edge.sizeOfArrays()] = 2, + AssertError); + } + } + } +#endif // NDEBUG +}