diff --git a/src/mesh/Connectivity.cpp b/src/mesh/Connectivity.cpp index de8be58168d312e083516e2824e5eec45a484e3c..a542c35e0a90463dd6c86af5672c0fbf45bf3244 100644 --- a/src/mesh/Connectivity.cpp +++ b/src/mesh/Connectivity.cpp @@ -82,7 +82,49 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) m_ref_node_list_vector = descriptor.template refItemListVector<ItemType::node>(); m_ref_cell_list_vector = descriptor.template refItemListVector<ItemType::cell>(); - if constexpr (Dimension > 1) { + if constexpr (Dimension == 1) { + // faces are similar to nodes + { + WeakFaceValue<int> face_number(*this); + face_number = convert_to_array(descriptor.node_number_vector); + m_face_number = face_number; + } + + { + WeakFaceValue<int> face_owner(*this); + face_owner = convert_to_array(descriptor.node_owner_vector); + m_face_owner = face_owner; + } + + { + const int rank = parallel::rank(); + WeakFaceValue<bool> face_is_owned(*this); + parallel_for( + this->numberOfFaces(), PUGS_LAMBDA(FaceId l) { face_is_owned[l] = (m_face_owner[l] == rank); }); + m_face_is_owned = face_is_owned; + } + + // edges are similar to nodes + { + WeakEdgeValue<int> edge_number(*this); + edge_number = convert_to_array(descriptor.node_number_vector); + m_edge_number = edge_number; + } + + { + WeakEdgeValue<int> edge_owner(*this); + edge_owner = convert_to_array(descriptor.node_owner_vector); + m_edge_owner = edge_owner; + } + + { + const int rank = parallel::rank(); + WeakEdgeValue<bool> edge_is_owned(*this); + parallel_for( + this->numberOfEdges(), PUGS_LAMBDA(EdgeId l) { edge_is_owned[l] = (m_edge_owner[l] == rank); }); + m_edge_is_owned = edge_is_owned; + } + } else { m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::node)] = descriptor.face_to_node_vector; m_item_to_item_matrix[itemTId(ItemType::cell)][itemTId(ItemType::face)] = descriptor.cell_to_face_vector; @@ -120,7 +162,29 @@ Connectivity<Dimension>::_buildFrom(const ConnectivityDescriptor& descriptor) m_ref_face_list_vector = descriptor.template refItemListVector<ItemType::face>(); - if constexpr (Dimension > 2) { + if constexpr (Dimension == 2) { + // edges are similar to faces + { + WeakEdgeValue<int> edge_number(*this); + edge_number = convert_to_array(descriptor.face_number_vector); + m_edge_number = edge_number; + } + + { + WeakEdgeValue<int> edge_owner(*this); + edge_owner = convert_to_array(descriptor.face_owner_vector); + m_edge_owner = edge_owner; + } + + { + const int rank = parallel::rank(); + WeakEdgeValue<bool> edge_is_owned(*this); + parallel_for( + this->numberOfEdges(), PUGS_LAMBDA(EdgeId l) { edge_is_owned[l] = (m_edge_owner[l] == rank); }); + m_edge_is_owned = edge_is_owned; + } + + } else { m_item_to_item_matrix[itemTId(ItemType::edge)][itemTId(ItemType::node)] = descriptor.edge_to_node_vector; m_item_to_item_matrix[itemTId(ItemType::face)][itemTId(ItemType::edge)] = descriptor.face_to_edge_vector; diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp index 2b25c6e9bf6f772acf5e0b02b9e93e9ea02a9877..5ca484b2258adfbe64b11cb6913c126442846447 100644 --- a/src/mesh/Connectivity.hpp +++ b/src/mesh/Connectivity.hpp @@ -196,7 +196,6 @@ class Connectivity final : public IConnectivity const auto& edgeOwner() const { - throw NotImplementedError("edge owner not built"); return m_edge_owner; } @@ -242,7 +241,6 @@ class Connectivity final : public IConnectivity const auto& edgeIsOwned() const { - throw NotImplementedError("edge is owned not built"); return m_edge_is_owned; } @@ -589,8 +587,14 @@ class Connectivity final : public IConnectivity size_t numberOfEdges() const final { - const auto& edge_to_node_matrix = this->_getMatrix(ItemType::edge, ItemType::node); - return edge_to_node_matrix.numRows(); + if constexpr (Dimension == 1) { + return this->numberOfNodes(); + } else if constexpr (Dimension == 2) { + return this->numberOfFaces(); + } else { + const auto& edge_to_node_matrix = this->_getMatrix(ItemType::edge, ItemType::node); + return edge_to_node_matrix.numRows(); + } } PUGS_INLINE diff --git a/src/mesh/ConnectivityDispatcher.cpp b/src/mesh/ConnectivityDispatcher.cpp index 6b73d967d4d4fcb37e1376bf1d9306826d25fb1f..1502bed705b252d9be19e1783ab7719488451c8c 100644 --- a/src/mesh/ConnectivityDispatcher.cpp +++ b/src/mesh/ConnectivityDispatcher.cpp @@ -29,7 +29,7 @@ ConnectivityDispatcher<Dimension>::_buildNewOwner() using ItemId = ItemIdT<item_type>; ItemValue<int, item_type> item_new_owner(m_connectivity); parallel_for( - item_new_owner.size(), PUGS_LAMBDA(const ItemId& l) { + item_new_owner.numberOfItems(), PUGS_LAMBDA(const ItemId& l) { const auto& item_to_cell = item_to_cell_matrix[l]; CellId Jmin = item_to_cell[0]; @@ -268,7 +268,7 @@ ConnectivityDispatcher<Dimension>::_buildNumberOfSubItemPerItemToRecvByProc() using ItemId = ItemIdT<SubItemOfItemT::item_type>; parallel_for( - number_of_sub_item_per_item.size(), + number_of_sub_item_per_item.numberOfItems(), PUGS_LAMBDA(const ItemId& j) { number_of_sub_item_per_item[j] = item_to_sub_item_matrix[j].size(); }); this->_dispatchedInfo<SubItemOfItemT>().m_number_of_sub_item_per_item_to_recv_by_proc = 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/ItemArray.hpp b/src/mesh/ItemArray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a38f950954084a3527717a2a858d452e3e3cf2ad --- /dev/null +++ b/src/mesh/ItemArray.hpp @@ -0,0 +1,219 @@ +#ifndef ITEM_ARRAY_HPP +#define ITEM_ARRAY_HPP + +#include <mesh/IConnectivity.hpp> +#include <mesh/ItemId.hpp> +#include <mesh/ItemType.hpp> +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/SubArray.hpp> + +#include <memory> + +template <typename DataType, ItemType item_type, typename ConnectivityPtr = std::shared_ptr<const IConnectivity>> +class ItemArray +{ + public: + static constexpr ItemType item_t{item_type}; + 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; + + Array<DataType> m_arrays_values; + + size_t m_size_of_arrays; + + // 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) + { + ItemArray<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image; + + image.m_connectivity_ptr = source.m_connectivity_ptr; + 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(); + } + } + + PUGS_INLINE + size_t + numberOfValues() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return m_arrays_values.size(); + } + + PUGS_INLINE + void + fill(const DataType& data) const noexcept + { + static_assert(not std::is_const_v<DataType>, "Cannot modify ItemArray of const"); + m_arrays_values.fill(data); + } + + // Following Kokkos logic, these classes are view and const view does allow + // changes in data + PUGS_FORCEINLINE + SubArray<DataType> + operator[](const ItemId& i) const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return SubArray{m_arrays_values, i * m_size_of_arrays, m_size_of_arrays}; + } + + template <typename IndexType> + SubArray<DataType> + operator[](const IndexType&) const noexcept(NO_ASSERT) + { + static_assert(std::is_same_v<IndexType, ItemId>, "ItemArray must be indexed by ItemId"); + } + + PUGS_INLINE + size_t + numberOfItems() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return m_connectivity_ptr->template numberOf<item_type>(); + } + + PUGS_INLINE + size_t + sizeOfArrays() const + { + Assert(this->isBuilt()); + return m_size_of_arrays; + } + + template <typename DataType2> + PUGS_INLINE ItemArray& + operator=(const Array<DataType2>& arrays) noexcept(NO_ASSERT) + { + // 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 ItemArray 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 ItemArray of const to ItemArray of non-const"); + + Assert((arrays.size() == 0) or this->isBuilt(), "Cannot assign array of arrays to a non-built ItemArray\n"); + + Assert(m_arrays_values.size() == arrays.size(), "Cannot assign an array of arrays of a different size\n"); + + m_arrays_values = arrays; + + return *this; + } + + template <typename DataType2, typename ConnectivityPtr2> + PUGS_INLINE ItemArray& + operator=(const ItemArray<DataType2, item_type, ConnectivityPtr2>& 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 ItemArray 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 ItemArray of const to ItemArray of non-const"); + + m_arrays_values = array_per_item.m_arrays_values; + m_size_of_arrays = 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 = array_per_item.m_connectivity_ptr.lock(); + } else { + m_connectivity_ptr = array_per_item.m_connectivity_ptr; + } + + return *this; + } + + template <typename DataType2, typename ConnectivityPtr2> + PUGS_INLINE + ItemArray(const ItemArray<DataType2, item_type, ConnectivityPtr2>& array_per_item) noexcept + { + this->operator=(array_per_item); + } + + PUGS_INLINE + ItemArray() = default; + + PUGS_INLINE + ItemArray(const IConnectivity& connectivity, size_t size_of_array) noexcept + : m_connectivity_ptr{connectivity.shared_ptr()}, + m_arrays_values{connectivity.numberOf<item_type>() * size_of_array}, + m_size_of_arrays{size_of_array} + { + static_assert(not std::is_const_v<DataType>, "Cannot allocate ItemArray of const data: only view is " + "supported"); + ; + } + + PUGS_INLINE + ~ItemArray() = default; +}; + +template <typename DataType> +using NodeArray = ItemArray<DataType, ItemType::node>; + +template <typename DataType> +using EdgeArray = ItemArray<DataType, ItemType::edge>; + +template <typename DataType> +using FaceArray = ItemArray<DataType, ItemType::face>; + +template <typename DataType> +using CellArray = ItemArray<DataType, ItemType::cell>; + +// Weak versions: should not be used outside of Connectivity + +template <typename DataType, ItemType item_type> +using WeakItemArray = ItemArray<DataType, item_type, std::weak_ptr<const IConnectivity>>; + +template <typename DataType> +using WeakNodeArray = WeakItemArray<DataType, ItemType::node>; + +template <typename DataType> +using WeakEdgeArray = WeakItemArray<DataType, ItemType::edge>; + +template <typename DataType> +using WeakFaceArray = WeakItemArray<DataType, ItemType::face>; + +template <typename DataType> +using WeakCellArray = WeakItemArray<DataType, ItemType::cell>; + +#endif // ITEM_ARRAY_HPP 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 a9049a394d225f68086a8c4038d8159928405612..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> @@ -37,16 +36,17 @@ class ItemValue // Allow const std:weak_ptr version to access our data friend ItemValue<std::add_const_t<DataType>, item_type, ConnectivityWeakPtr>; + public: friend PUGS_INLINE ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> copy(const ItemValue<DataType, item_type, ConnectivityPtr>& source) { - ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image(*source.connectivity_ptr()); + ItemValue<std::remove_const_t<DataType>, item_type, ConnectivityPtr> image; - image.m_values = copy(source.m_values); + image.m_connectivity_ptr = source.m_connectivity_ptr; + image.m_values = copy(source.m_values); return image; } - public: PUGS_INLINE bool isBuilt() const noexcept @@ -67,7 +67,7 @@ class ItemValue PUGS_INLINE size_t - size() const noexcept(NO_ASSERT) + numberOfItems() const noexcept(NO_ASSERT) { Assert(this->isBuilt()); return m_values.size(); @@ -84,26 +84,20 @@ class ItemValue // Following Kokkos logic, these classes are view and const view does allow // changes in data PUGS_FORCEINLINE - DataType& operator[](const ItemId& i) const noexcept(NO_ASSERT) + DataType& + operator[](const ItemId& i) const noexcept(NO_ASSERT) { Assert(this->isBuilt()); return m_values[i]; } template <typename IndexType> - DataType& operator[](const IndexType&) const noexcept(NO_ASSERT) + DataType& + operator[](const IndexType&) const noexcept(NO_ASSERT) { static_assert(std::is_same_v<IndexType, ItemId>, "ItemValue must be indexed by ItemId"); } - PUGS_INLINE - size_t - numberOfItems() const noexcept(NO_ASSERT) - { - Assert(this->isBuilt()); - return m_values.size(); - } - template <typename DataType2> PUGS_INLINE ItemValue& operator=(const Array<DataType2>& values) noexcept(NO_ASSERT) @@ -162,7 +156,6 @@ class ItemValue { static_assert(not std::is_const_v<DataType>, "Cannot allocate ItemValue of const data: only view is " "supported"); - ; } PUGS_INLINE diff --git a/src/mesh/ItemValueUtils.hpp b/src/mesh/ItemValueUtils.hpp index a1039fdbdc8933c27d6ce19ec978894b329520c1..c307ce4d6010e9ce0d40b4afdcb2ab4466e1d009 100644 --- a/src/mesh/ItemValueUtils.hpp +++ b/src/mesh/ItemValueUtils.hpp @@ -32,7 +32,7 @@ min(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) operator data_type() { data_type reduced_value; - parallel_reduce(m_item_value.size(), *this, reduced_value); + parallel_reduce(m_item_value.numberOfItems(), *this, reduced_value); return reduced_value; } @@ -50,7 +50,8 @@ min(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) join(volatile data_type& dst, const volatile data_type& src) const { if (src < dst) { - dst = src; + // cannot be reached if initial value is the min + dst = src; // LCOV_EXCL_LINE } } @@ -83,9 +84,11 @@ min(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) return connectivity_3d.isOwned<item_type>(); break; } + // LCOV_EXCL_START default: { throw UnexpectedError("unexpected dimension"); } + // LCOV_EXCL_STOP } }(*item_value.connectivity_ptr())) { @@ -121,7 +124,7 @@ max(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) operator data_type() { data_type reduced_value; - parallel_reduce(m_item_value.size(), *this, reduced_value); + parallel_reduce(m_item_value.numberOfItems(), *this, reduced_value); return reduced_value; } @@ -139,7 +142,8 @@ max(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) join(volatile data_type& dst, const volatile data_type& src) const { if (src > dst) { - dst = src; + // cannot be reached if initial value is the max + dst = src; // LCOV_EXCL_LINE } } @@ -172,9 +176,11 @@ max(const ItemValue<DataType, item_type, ConnectivityPtr>& item_value) return connectivity_3d.isOwned<item_type>(); break; } + // LCOV_EXCL_START default: { throw UnexpectedError("unexpected dimension"); } + // LCOV_EXCL_STOP } }(*item_value.connectivity_ptr())) { @@ -211,7 +217,7 @@ sum(const ItemValue<DataType, item_type>& item_value) operator data_type() { data_type reduced_value; - parallel_reduce(m_item_value.size(), *this, reduced_value); + parallel_reduce(m_item_value.numberOfItems(), *this, reduced_value); return reduced_value; } @@ -264,9 +270,11 @@ sum(const ItemValue<DataType, item_type>& item_value) return connectivity_3d.isOwned<item_type>(); break; } + // LCOV_EXCL_START default: { throw UnexpectedError("unexpected dimension"); } + // LCOV_EXCL_STOP } }(*item_value.connectivity_ptr())) { diff --git a/src/mesh/Mesh.hpp b/src/mesh/Mesh.hpp index 21c100384ef2072e43af54dda74eda8d6021c2ea..45f4c8d050d7fd7c63e44caf002b6bbcb1c7599a 100644 --- a/src/mesh/Mesh.hpp +++ b/src/mesh/Mesh.hpp @@ -49,6 +49,13 @@ class Mesh final : public IMesh return m_connectivity->numberOfNodes(); } + PUGS_INLINE + size_t + numberOfEdges() const + { + return m_connectivity->numberOfEdges(); + } + PUGS_INLINE size_t numberOfFaces() const 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/src/mesh/SubItemValuePerItem.hpp b/src/mesh/SubItemValuePerItem.hpp index 66af694c7255da41ff7570d294dd4777acb0164f..63bff8a35848746535df9d05c7df0a12c899c3a6 100644 --- a/src/mesh/SubItemValuePerItem.hpp +++ b/src/mesh/SubItemValuePerItem.hpp @@ -41,6 +41,12 @@ class SubItemValuePerItem // Allow const std:weak_ptr version to access our data friend SubItemValuePerItem<std::add_const_t<DataType>, ItemOfItem, ConnectivityWeakPtr>; + // Allow const std:shared_ptr version to access our data + friend SubItemValuePerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivitySharedPtr>; + + // Allow const std:weak_ptr version to access our data + friend SubItemValuePerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivityWeakPtr>; + public: using ToShared = SubItemValuePerItem<DataType, ItemOfItem, ConnectivitySharedPtr>; @@ -55,7 +61,8 @@ class SubItemValuePerItem public: template <typename IndexType> - PUGS_INLINE const DataType& operator[](IndexType i) const noexcept(NO_ASSERT) + PUGS_FORCEINLINE DataType& + operator[](IndexType i) const noexcept(NO_ASSERT) { static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral values"); Assert(i < m_size); @@ -63,7 +70,8 @@ class SubItemValuePerItem } template <typename IndexType> - PUGS_FORCEINLINE DataType& operator[](IndexType i) noexcept(NO_ASSERT) + PUGS_FORCEINLINE DataType& + operator[](IndexType i) noexcept(NO_ASSERT) { static_assert(std::is_integral_v<IndexType>, "SubView is indexed by integral values"); Assert(i < m_size); @@ -77,10 +85,8 @@ class SubItemValuePerItem return m_size; } - SubView(const SubView&) = delete; - - PUGS_INLINE - SubView(SubView&&) noexcept = default; + SubView(const SubView&) = delete; + SubView(SubView&&) noexcept = delete; PUGS_INLINE SubView(const Array<DataType>& values, size_t begin, size_t end) noexcept(NO_ASSERT) @@ -89,8 +95,21 @@ class SubItemValuePerItem Assert(begin <= end); Assert(end <= values.size()); } + + ~SubView() = default; }; + friend PUGS_INLINE SubItemValuePerItem<std::remove_const_t<DataType>, ItemOfItem, ConnectivityPtr> + copy(SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& source) + { + SubItemValuePerItem<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_values = copy(source.m_values); + return image; + } + PUGS_INLINE bool isBuilt() const noexcept @@ -98,6 +117,17 @@ class SubItemValuePerItem 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 DataType& operator()(IndexType item_id, SubIndexType i) const noexcept(NO_ASSERT) @@ -109,32 +139,33 @@ class SubItemValuePerItem return m_values[m_host_row_map(size_t{item_id}) + i]; } - PUGS_INLINE - size_t - numberOfValues() const noexcept(NO_ASSERT) - { - Assert(this->isBuilt()); - return m_values.size(); - } - // 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) + 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(i < m_values.size()); + Assert(static_cast<size_t>(i) < m_values.size()); return m_values[i]; } + PUGS_INLINE + size_t + numberOfValues() const noexcept(NO_ASSERT) + { + Assert(this->isBuilt()); + return m_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); + Assert(m_host_row_map.extent(0) > 0); + return m_host_row_map.extent(0) - 1; } template <typename IndexType> @@ -143,7 +174,7 @@ class SubItemValuePerItem { static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - Assert(item_id < m_host_row_map.extent(0)); + Assert(item_id < this->numberOfItems()); return m_host_row_map(size_t{item_id} + 1) - m_host_row_map(size_t{item_id}); } @@ -153,7 +184,7 @@ class SubItemValuePerItem { static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - Assert(item_id < m_host_row_map.extent(0)); + 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_values, item_begin, item_end); @@ -167,7 +198,7 @@ class SubItemValuePerItem { static_assert(std::is_same_v<IndexType, ItemId>, "index must be an ItemId"); Assert(this->isBuilt()); - Assert(item_id < m_host_row_map.extent(0)); + 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_values, item_begin, item_end); @@ -211,7 +242,6 @@ class SubItemValuePerItem { static_assert(not std::is_const_v<DataType>, "Cannot allocate SubItemValuePerItem of const data: only " "view is supported"); - ; ConnectivityMatrix connectivity_matrix = connectivity._getMatrix(item_type, sub_item_type); diff --git a/src/mesh/Synchronizer.hpp b/src/mesh/Synchronizer.hpp index d23634ac3db35a026b50cb4bd0f8c040c80aa4cd..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> @@ -66,7 +67,7 @@ class Synchronizer auto& requested_item_info = this->_getRequestedItemInfo<item_type>(); requested_item_info = [&]() { std::vector<std::vector<ItemId>> requested_item_vector_info(parallel::size()); - for (ItemId item_id = 0; item_id < item_owner.size(); ++item_id) { + for (ItemId item_id = 0; item_id < item_owner.numberOfItems(); ++item_id) { if (const size_t owner = item_owner[item_id]; owner != parallel::rank()) { requested_item_vector_info[owner].emplace_back(item_id); } @@ -105,7 +106,7 @@ class Synchronizer parallel::exchange(requested_item_number_list_by_proc, provided_item_number_list_by_rank); std::map<int, ItemId> item_number_to_id_correspondance; - for (ItemId item_id = 0; item_id < item_number.size(); ++item_id) { + for (ItemId item_id = 0; item_id < item_number.numberOfItems(); ++item_id) { item_number_to_id_correspondance[item_number[item_id]] = item_id; } @@ -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/src/output/GnuplotWriter1D.cpp b/src/output/GnuplotWriter1D.cpp index b25ca82accf3189fbdab58ca4161101647cb463d..79423d5da05b699b995d472313e134a8c9dd4a52 100644 --- a/src/output/GnuplotWriter1D.cpp +++ b/src/output/GnuplotWriter1D.cpp @@ -182,7 +182,7 @@ GnuplotWriter1D::_writeItemValues(const std::shared_ptr<const MeshType>& mesh, if constexpr (ItemValueT::item_t == item_type) { using DataT = std::decay_t<typename ItemValueT::data_type>; size_t index = 0; - for (ItemId item_id = 0; item_id < item_value.size(); ++item_id) { + for (ItemId item_id = 0; item_id < item_value.numberOfItems(); ++item_id) { if (is_owned[item_id]) { if constexpr (std::is_arithmetic_v<DataT>) { values[number_of_columns * index + column_number] = item_value[item_id]; diff --git a/src/utils/SubArray.hpp b/src/utils/SubArray.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a5019dec9521039e420aeeef48c0439930a7840c --- /dev/null +++ b/src/utils/SubArray.hpp @@ -0,0 +1,78 @@ +#ifndef SUB_ARRAY_HPP +#define SUB_ARRAY_HPP + +#include <utils/Array.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/PugsMacros.hpp> +#include <utils/PugsUtils.hpp> + +#include <algorithm> + +template <typename DataType> +class [[nodiscard]] SubArray +{ + public: + using data_type = DataType; + using index_type = size_t; + + private: + PUGS_RESTRICT DataType* const m_sub_values; + const size_t m_size; + + // Allows const version to access our data + friend SubArray<std::add_const_t<DataType>>; + + public: + PUGS_INLINE size_t size() const noexcept + { + return m_size; + } + + PUGS_INLINE DataType& operator[](index_type i) const noexcept(NO_ASSERT) + { + Assert(i < m_size); + return m_sub_values[i]; + } + + PUGS_INLINE + void fill(const DataType& data) const + { + static_assert(not std::is_const<DataType>(), "Cannot modify SubArray of const"); + + // could consider to use std::fill + parallel_for( + this->size(), PUGS_LAMBDA(index_type i) { m_sub_values[i] = data; }); + } + + PUGS_INLINE + SubArray& operator=(const SubArray&) = delete; + + PUGS_INLINE + SubArray& operator=(SubArray&&) = delete; + + PUGS_INLINE + explicit SubArray(const Array<DataType>& array, size_t begin, size_t size) + : m_sub_values{&array[0] + begin}, m_size{size} + { + Assert(begin + size <= array.size(), "SubView is not contained in the source Array"); + } + + PUGS_INLINE + explicit SubArray(DataType* const raw_array, size_t begin, size_t size) + : m_sub_values{raw_array + begin}, m_size{size} + {} + + PUGS_INLINE + SubArray() = delete; + + PUGS_INLINE + SubArray(const SubArray&) = delete; + + PUGS_INLINE + SubArray(SubArray &&) = delete; + + PUGS_INLINE + ~SubArray() = default; +}; + +#endif // SUB_ARRAY_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c4413ddc7c6f06665b4efb7b091548fb26140fab..c99154ff0dee78cf7aadf95c70cccfbeb36ffa75 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -85,6 +85,7 @@ add_executable (unit_tests test_PugsUtils.cpp test_RevisionInfo.cpp test_SparseMatrixDescriptor.cpp + test_SubArray.cpp test_SymbolTable.cpp test_Timer.cpp test_TinyMatrix.cpp @@ -99,6 +100,12 @@ add_executable (mpi_unit_tests mpi_test_main.cpp test_Messenger.cpp test_Partitioner.cpp + test_ItemArray.cpp + test_ItemArrayUtils.cpp + test_ItemValue.cpp + test_ItemValueUtils.cpp + test_SubItemValuePerItem.cpp + test_SubItemArrayPerItem.cpp ) add_library(test_Pugs_MeshDataBase diff --git a/tests/test_ItemArray.cpp b/tests/test_ItemArray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2177d83c2df0dd70674803e7098d0f6b694b9685 --- /dev/null +++ b/tests/test_ItemArray.cpp @@ -0,0 +1,256 @@ +#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/Mesh.hpp> +#include <utils/Messenger.hpp> + +template class ItemArray<int, ItemType::node>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ItemArray", "[mesh]") +{ + SECTION("default constructors") + { + REQUIRE_NOTHROW(NodeArray<int>{}); + REQUIRE_NOTHROW(EdgeArray<int>{}); + REQUIRE_NOTHROW(FaceArray<int>{}); + REQUIRE_NOTHROW(CellArray<int>{}); + + REQUIRE(not NodeArray<int>{}.isBuilt()); + REQUIRE(not EdgeArray<int>{}.isBuilt()); + REQUIRE(not FaceArray<int>{}.isBuilt()); + REQUIRE(not CellArray<int>{}.isBuilt()); + } + + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); + + REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); + + NodeArray<int> node_value{connectivity, 3}; + EdgeArray<int> edge_value{connectivity, 3}; + FaceArray<int> face_value{connectivity, 3}; + CellArray<int> cell_value{connectivity, 3}; + + REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); + + REQUIRE(node_value.numberOfValues() == 3 * node_value.numberOfItems()); + REQUIRE(edge_value.numberOfValues() == 3 * edge_value.numberOfItems()); + REQUIRE(face_value.numberOfValues() == 3 * face_value.numberOfItems()); + REQUIRE(cell_value.numberOfValues() == 3 * cell_value.numberOfItems()); + + REQUIRE(node_value.sizeOfArrays() == 3); + REQUIRE(edge_value.sizeOfArrays() == 3); + REQUIRE(face_value.sizeOfArrays() == 3); + REQUIRE(cell_value.sizeOfArrays() == 3); + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 2}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 2}); + + REQUIRE(NodeArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 2}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 2}.isBuilt()); + + NodeArray<int> node_value{connectivity, 2}; + EdgeArray<int> edge_value{connectivity, 2}; + FaceArray<int> face_value{connectivity, 2}; + CellArray<int> cell_value{connectivity, 2}; + + REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); + + REQUIRE(node_value.numberOfValues() == 2 * node_value.numberOfItems()); + REQUIRE(edge_value.numberOfValues() == 2 * edge_value.numberOfItems()); + REQUIRE(face_value.numberOfValues() == 2 * face_value.numberOfItems()); + REQUIRE(cell_value.numberOfValues() == 2 * cell_value.numberOfItems()); + + REQUIRE(node_value.sizeOfArrays() == 2); + REQUIRE(edge_value.sizeOfArrays() == 2); + REQUIRE(face_value.sizeOfArrays() == 2); + REQUIRE(cell_value.sizeOfArrays() == 2); + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + REQUIRE_NOTHROW(NodeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(EdgeArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(FaceArray<int>{connectivity, 3}); + REQUIRE_NOTHROW(CellArray<int>{connectivity, 3}); + + REQUIRE(NodeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(EdgeArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(FaceArray<int>{connectivity, 3}.isBuilt()); + REQUIRE(CellArray<int>{connectivity, 3}.isBuilt()); + + NodeArray<int> node_value{connectivity, 3}; + EdgeArray<int> edge_value{connectivity, 3}; + FaceArray<int> face_value{connectivity, 3}; + CellArray<int> cell_value{connectivity, 3}; + + REQUIRE(node_value.numberOfValues() == 3 * node_value.numberOfItems()); + REQUIRE(edge_value.numberOfValues() == 3 * edge_value.numberOfItems()); + REQUIRE(face_value.numberOfValues() == 3 * face_value.numberOfItems()); + REQUIRE(cell_value.numberOfValues() == 3 * cell_value.numberOfItems()); + + REQUIRE(node_value.sizeOfArrays() == 3); + REQUIRE(edge_value.sizeOfArrays() == 3); + REQUIRE(face_value.sizeOfArrays() == 3); + REQUIRE(cell_value.sizeOfArrays() == 3); + } + + SECTION("set values from array") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellArray<size_t> cell_array{connectivity, 3}; + + Array<size_t> array{cell_array.numberOfValues()}; + for (size_t i = 0; i < array.size(); ++i) { + array[i] = i; + } + + cell_array = array; + + auto is_same = [](const CellArray<size_t>& cell_array, const Array<size_t>& array) { + bool is_same = true; + size_t k = 0; + for (CellId cell_id = 0; cell_id < cell_array.numberOfItems(); ++cell_id) { + SubArray sub_array = cell_array[cell_id]; + for (size_t i = 0; i < sub_array.size(); ++i, ++k) { + is_same &= (sub_array[i] == array[k]); + } + } + return is_same; + }; + + REQUIRE(is_same(cell_array, array)); + } + + SECTION("copy") + { + auto is_same = [](const auto& cell_array, int value) { + bool is_same = true; + for (CellId cell_id = 0; cell_id < cell_array.numberOfItems(); ++cell_id) { + SubArray sub_array = cell_array[cell_id]; + for (size_t i = 0; i < sub_array.size(); ++i) { + is_same &= (sub_array[i] == value); + } + } + return is_same; + }; + + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellArray<int> cell_array{connectivity, 4}; + cell_array.fill(parallel::rank()); + + CellArray<const int> cell_array_const_view{cell_array}; + REQUIRE(cell_array.numberOfValues() == cell_array_const_view.numberOfValues()); + REQUIRE(is_same(cell_array_const_view, static_cast<std::int64_t>(parallel::rank()))); + + CellArray<const int> const_cell_array; + const_cell_array = copy(cell_array); + + cell_array.fill(0); + + REQUIRE(is_same(cell_array, 0)); + REQUIRE(is_same(cell_array_const_view, 0)); + REQUIRE(is_same(const_cell_array, static_cast<std::int64_t>(parallel::rank()))); + } + + SECTION("WeakItemArray") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + WeakFaceArray<int> weak_face_array{connectivity, 5}; + + weak_face_array.fill(parallel::rank()); + + FaceArray<const int> face_array{weak_face_array}; + + REQUIRE(face_array.connectivity_ptr() == weak_face_array.connectivity_ptr()); + } + +#ifndef NDEBUG + SECTION("error") + { + SECTION("checking for build ItemArray") + { + CellArray<int> cell_array; + REQUIRE_THROWS_AS(cell_array[CellId{0}], AssertError); + + FaceArray<int> face_array; + REQUIRE_THROWS_AS(face_array[FaceId{0}], AssertError); + + EdgeArray<int> edge_array; + REQUIRE_THROWS_AS(edge_array[EdgeId{0}], AssertError); + + NodeArray<int> node_array; + REQUIRE_THROWS_AS(node_array[NodeId{0}], AssertError); + } + + SECTION("checking for bounds violation") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellArray<int> cell_array{connectivity, 1}; + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(cell_array[invalid_cell_id], AssertError); + + FaceArray<int> face_array{connectivity, 2}; + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(face_array[invalid_face_id], AssertError); + + EdgeArray<int> edge_array{connectivity, 1}; + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(edge_array[invalid_edge_id], AssertError); + + NodeArray<int> node_array{connectivity, 0}; + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(node_array[invalid_node_id], AssertError); + } + + SECTION("set values from invalid array size") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellArray<size_t> cell_array{connectivity, 2}; + + Array<size_t> values{3 + cell_array.numberOfValues()}; + REQUIRE_THROWS_AS(cell_array = values, AssertError); + } + } +#endif // NDEBUG +} 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); + } + } + } + } +} diff --git a/tests/test_ItemValue.cpp b/tests/test_ItemValue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..942b4f57bafd0528ed31e82709213207c2dea619 --- /dev/null +++ b/tests/test_ItemValue.cpp @@ -0,0 +1,196 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/Mesh.hpp> +#include <utils/Messenger.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ItemValue", "[mesh]") +{ + SECTION("default constructors") + { + REQUIRE_NOTHROW(NodeValue<int>{}); + REQUIRE_NOTHROW(EdgeValue<int>{}); + REQUIRE_NOTHROW(FaceValue<int>{}); + REQUIRE_NOTHROW(CellValue<int>{}); + + REQUIRE(not NodeValue<int>{}.isBuilt()); + REQUIRE(not EdgeValue<int>{}.isBuilt()); + REQUIRE(not FaceValue<int>{}.isBuilt()); + REQUIRE(not CellValue<int>{}.isBuilt()); + } + + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); + + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); + + NodeValue<int> node_value{connectivity}; + EdgeValue<int> edge_value{connectivity}; + FaceValue<int> face_value{connectivity}; + CellValue<int> cell_value{connectivity}; + + REQUIRE(edge_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(face_value.numberOfItems() == node_value.numberOfItems()); + REQUIRE(cell_value.numberOfItems() + 1 == node_value.numberOfItems()); + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); + + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); + + EdgeValue<int> edge_value{connectivity}; + FaceValue<int> face_value{connectivity}; + + REQUIRE(edge_value.numberOfItems() == face_value.numberOfItems()); + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + REQUIRE_NOTHROW(NodeValue<int>{connectivity}); + REQUIRE_NOTHROW(EdgeValue<int>{connectivity}); + REQUIRE_NOTHROW(FaceValue<int>{connectivity}); + REQUIRE_NOTHROW(CellValue<int>{connectivity}); + + REQUIRE(NodeValue<int>{connectivity}.isBuilt()); + REQUIRE(EdgeValue<int>{connectivity}.isBuilt()); + REQUIRE(FaceValue<int>{connectivity}.isBuilt()); + REQUIRE(CellValue<int>{connectivity}.isBuilt()); + } + + SECTION("set values from array") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + + Array<size_t> values{cell_value.numberOfItems()}; + for (size_t i = 0; i < values.size(); ++i) { + values[i] = i; + } + + cell_value = values; + + for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { + REQUIRE(cell_value[i_cell] == i_cell); + } + } + + SECTION("copy") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(parallel::rank()); + + CellValue<const int> const_cell_value; + const_cell_value = copy(cell_value); + + cell_value.fill(0); + + for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { + REQUIRE(cell_value[i_cell] == 0); + } + + for (CellId i_cell = 0; i_cell < mesh_3d.numberOfCells(); ++i_cell) { + REQUIRE(const_cell_value[i_cell] == static_cast<std::int64_t>(parallel::rank())); + } + } + + SECTION("WeakItemValue") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + WeakFaceValue<int> weak_face_value{connectivity}; + + weak_face_value.fill(parallel::rank()); + + FaceValue<const int> face_value{weak_face_value}; + + REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + } + +#ifndef NDEBUG + SECTION("error") + { + SECTION("checking for build ItemValue") + { + CellValue<int> cell_value; + REQUIRE_THROWS_AS(cell_value[CellId{0}], AssertError); + + FaceValue<int> face_value; + REQUIRE_THROWS_AS(face_value[FaceId{0}], AssertError); + + EdgeValue<int> edge_value; + REQUIRE_THROWS_AS(edge_value[EdgeId{0}], AssertError); + + NodeValue<int> node_value; + REQUIRE_THROWS_AS(node_value[NodeId{0}], AssertError); + } + + SECTION("checking for bounds violation") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<int> cell_value{connectivity}; + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(cell_value[invalid_cell_id], AssertError); + + FaceValue<int> face_value{connectivity}; + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(face_value[invalid_face_id], AssertError); + + EdgeValue<int> edge_value{connectivity}; + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(edge_value[invalid_edge_id], AssertError); + + NodeValue<int> node_value{connectivity}; + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(node_value[invalid_node_id], AssertError); + } + + SECTION("set values from invalid array size") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + + Array<size_t> values{3 + cell_value.numberOfItems()}; + REQUIRE_THROWS_AS(cell_value = values, AssertError); + } + } +#endif // NDEBUG +} diff --git a/tests/test_ItemValueUtils.cpp b/tests/test_ItemValueUtils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f54362188d6e9519d28abb47e69385ba11ccfdb8 --- /dev/null +++ b/tests/test_ItemValueUtils.cpp @@ -0,0 +1,241 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <MeshDataBaseForTests.hpp> +#include <mesh/Connectivity.hpp> +#include <mesh/ItemValue.hpp> +#include <mesh/ItemValueUtils.hpp> +#include <mesh/Mesh.hpp> +#include <utils/Messenger.hpp> + +// Instantiate to ensure full coverage is performed +template class ItemValue<int, ItemType::cell>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ItemValueUtils", "[mesh]") +{ + SECTION("Synchronize") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + WeakFaceValue<int> weak_face_value{connectivity}; + + weak_face_value.fill(parallel::rank()); + + FaceValue<const int> face_value{weak_face_value}; + + REQUIRE(face_value.connectivity_ptr() == weak_face_value.connectivity_ptr()); + + { // before synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { + if (face_is_owned[i_face]) { + REQUIRE(face_owner[i_face] == face_value[i_face]); + } else { + REQUIRE(face_owner[i_face] != face_value[i_face]); + } + } + } + + synchronize(weak_face_value); + + { // after synchronization + auto face_owner = connectivity.faceOwner(); + auto face_is_owned = connectivity.faceIsOwned(); + + for (FaceId i_face = 0; i_face < mesh_2d.numberOfFaces(); ++i_face) { + REQUIRE(face_owner[i_face] == face_value[i_face]); + } + } + } + + SECTION("min") + { + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_1d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); + + REQUIRE(min(cell_value) == 10); + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_2d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); + + REQUIRE(min(cell_value) == 10); + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<int> cell_value{connectivity}; + cell_value.fill(-1); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_3d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = 10 + parallel::rank(); + } + }); + + REQUIRE(min(cell_value) == 10); + } + } + + SECTION("max") + { + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_1d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); + + REQUIRE(max(cell_value) == parallel::size()); + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_2d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); + + REQUIRE(max(cell_value) == parallel::size()); + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(std::numeric_limits<size_t>::max()); + + auto cell_is_owned = connectivity.cellIsOwned(); + parallel_for( + mesh_3d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { + if (cell_is_owned[cell_id]) { + cell_value[cell_id] = parallel::rank() + 1; + } + }); + + REQUIRE(max(cell_value) == parallel::size()); + } + } + + SECTION("sum") + { + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + CellValue<size_t> cell_value{connectivity}; + cell_value.fill(5); + + auto cell_is_owned = connectivity.cellIsOwned(); + + const size_t global_number_of_cells = [&] { + size_t number_of_cells = 0; + for (CellId cell_id = 0; cell_id < cell_is_owned.numberOfItems(); ++cell_id) { + number_of_cells += cell_is_owned[cell_id]; + } + return parallel::allReduceSum(number_of_cells); + }(); + + REQUIRE(sum(cell_value) == 5 * global_number_of_cells); + } + + SECTION("2D") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + FaceValue<size_t> face_value{connectivity}; + face_value.fill(2); + + auto face_is_owned = connectivity.faceIsOwned(); + + const size_t global_number_of_faces = [&] { + size_t number_of_faces = 0; + for (FaceId face_id = 0; face_id < face_is_owned.numberOfItems(); ++face_id) { + number_of_faces += face_is_owned[face_id]; + } + return parallel::allReduceSum(number_of_faces); + }(); + + REQUIRE(sum(face_value) == 2 * global_number_of_faces); + } + + SECTION("3D") + { + const Mesh<Connectivity<3>>& mesh_3d = MeshDataBaseForTests::get().cartesianMesh<3>(); + const Connectivity<3>& connectivity = mesh_3d.connectivity(); + + NodeValue<size_t> node_value{connectivity}; + node_value.fill(3); + + auto node_is_owned = connectivity.nodeIsOwned(); + + const size_t global_number_of_nodes = [&] { + size_t number_of_nodes = 0; + for (NodeId node_id = 0; node_id < node_is_owned.numberOfItems(); ++node_id) { + number_of_nodes += node_is_owned[node_id]; + } + return parallel::allReduceSum(number_of_nodes); + }(); + + REQUIRE(sum(node_value) == 3 * global_number_of_nodes); + } + } +} diff --git a/tests/test_SubArray.cpp b/tests/test_SubArray.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b0fdec7882d7ee3504cb24bdfb76b796649f8202 --- /dev/null +++ b/tests/test_SubArray.cpp @@ -0,0 +1,66 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <utils/PugsAssert.hpp> +#include <utils/SubArray.hpp> +#include <utils/Types.hpp> + +// Instantiate to ensure full coverage is performed +template class SubArray<int>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SubArray", "[utils]") +{ + Array<int> a(10); + REQUIRE(a.size() == 10); + + SECTION("shared values") + { + SubArray sub_a{a, 0, 10}; + for (size_t i = 0; i < sub_a.size(); ++i) { + sub_a[i] = 2 * i; + } + + REQUIRE(((a[0] == 0) and (a[1] == 2) and (a[2] == 4) and (a[3] == 6) and (a[4] == 8) and (a[5] == 10) and + (a[6] == 12) and (a[7] == 14) and (a[8] == 16) and (a[9] == 18))); + + for (size_t i = 0; i < a.size(); ++i) { + a[i] = (i + 1) * (2 * i + 1); + } + + REQUIRE(((sub_a[0] == 1) and (sub_a[1] == 6) and (sub_a[2] == 15) and (sub_a[3] == 28) and (sub_a[4] == 45) and + (sub_a[5] == 66) and (sub_a[6] == 91) and (sub_a[7] == 120) and (sub_a[8] == 153) and (sub_a[9] == 190))); + } + + SECTION("sub array") + { + a.fill(0); + SubArray sub_a{a, 5, 5}; + for (size_t i = 0; i < sub_a.size(); ++i) { + sub_a[i] = i + 1; + } + + REQUIRE(((a[0] == 0) and (a[1] == 0) and (a[2] == 0) and (a[3] == 0) and (a[4] == 0) and (a[5] == 1) and + (a[6] == 2) and (a[7] == 3) and (a[8] == 4) and (a[9] == 5))); + + for (size_t i = 0; i < a.size(); ++i) { + a[i] = (i + 1) * (2 * i + 1); + } + + REQUIRE(((sub_a[0] == 66) and (sub_a[1] == 91) and (sub_a[2] == 120) and (sub_a[3] == 153) and (sub_a[4] == 190))); + } + +#ifndef NDEBUG + SECTION("errors") + { + a.fill(0); + SubArray<int> sub_a{a, 5, 5}; + for (size_t i = 0; i < sub_a.size(); ++i) { + sub_a[i] = i + 1; + } + + REQUIRE_THROWS_AS(sub_a[5], AssertError); + } +#endif // NDEBUG +} 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 +} diff --git a/tests/test_SubItemValuePerItem.cpp b/tests/test_SubItemValuePerItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7c9434aa7362f7cb27a87ee6b144df27f9c2f26 --- /dev/null +++ b/tests/test_SubItemValuePerItem.cpp @@ -0,0 +1,818 @@ +#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/SubItemValuePerItem.hpp> +#include <utils/Messenger.hpp> + +// Instantiate to ensure full coverage is performed +template class SubItemValuePerItem<size_t, NodeOfCell>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SubItemValuePerItem", "[mesh]") +{ + SECTION("default constructors") + { + REQUIRE_NOTHROW(NodeValuePerEdge<int>{}); + REQUIRE_NOTHROW(NodeValuePerFace<int>{}); + REQUIRE_NOTHROW(NodeValuePerCell<int>{}); + + REQUIRE_NOTHROW(EdgeValuePerNode<int>{}); + REQUIRE_NOTHROW(EdgeValuePerFace<int>{}); + REQUIRE_NOTHROW(EdgeValuePerCell<int>{}); + + REQUIRE_NOTHROW(FaceValuePerNode<int>{}); + REQUIRE_NOTHROW(FaceValuePerEdge<int>{}); + REQUIRE_NOTHROW(FaceValuePerCell<int>{}); + + REQUIRE_NOTHROW(CellValuePerNode<int>{}); + REQUIRE_NOTHROW(CellValuePerEdge<int>{}); + REQUIRE_NOTHROW(CellValuePerFace<int>{}); + + REQUIRE(not NodeValuePerEdge<int>{}.isBuilt()); + REQUIRE(not NodeValuePerFace<int>{}.isBuilt()); + REQUIRE(not NodeValuePerCell<int>{}.isBuilt()); + + REQUIRE(not EdgeValuePerNode<int>{}.isBuilt()); + REQUIRE(not EdgeValuePerFace<int>{}.isBuilt()); + REQUIRE(not EdgeValuePerCell<int>{}.isBuilt()); + + REQUIRE(not FaceValuePerNode<int>{}.isBuilt()); + REQUIRE(not FaceValuePerEdge<int>{}.isBuilt()); + REQUIRE(not FaceValuePerCell<int>{}.isBuilt()); + + REQUIRE(not CellValuePerNode<int>{}.isBuilt()); + REQUIRE(not CellValuePerEdge<int>{}.isBuilt()); + REQUIRE(not CellValuePerFace<int>{}.isBuilt()); + } + + SECTION("dimensions") + { + auto number_of_values = [](const auto& sub_item_value_per_item) -> size_t { + using SubItemValuePerItemType = std::decay_t<decltype(sub_item_value_per_item)>; + using ItemId = typename SubItemValuePerItemType::ItemId; + + size_t number = 0; + for (ItemId item_id = 0; item_id < sub_item_value_per_item.numberOfItems(); ++item_id) { + number += sub_item_value_per_item.numberOfSubValues(item_id); + } + return number; + }; + + SECTION("1D") + { + const Mesh<Connectivity<1>>& mesh_1d = MeshDataBaseForTests::get().cartesianMesh<1>(); + const Connectivity<1>& connectivity = mesh_1d.connectivity(); + + SECTION("per cell") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)) and + (node_value_per_cell.itemValues(cell_id).size() == node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + const NodeValuePerCell<const int> const_node_value_per_cell = node_value_per_cell; + { + bool is_correct = true; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + is_correct &= + (const_node_value_per_cell.itemValues(cell_id).size() == node_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + 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_value_per_node.numberOfSubValues(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") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerFace<int> node_value_per_face{connectivity}; + REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeValuePerNode<int> edge_value_per_node{connectivity}; + REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); + + 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_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerNode<int> face_value_per_node{connectivity}; + REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); + + 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_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + 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_value_per_node.numberOfSubValues(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") + { + NodeValuePerCell<int> node_value_per_cell{connectivity}; + REQUIRE(node_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(node_value_per_cell.numberOfValues() == number_of_values(node_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + REQUIRE(edge_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(edge_value_per_cell.numberOfValues() == number_of_values(edge_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerCell<int> face_value_per_cell{connectivity}; + REQUIRE(face_value_per_cell.numberOfItems() == connectivity.numberOfCells()); + REQUIRE(face_value_per_cell.numberOfValues() == number_of_values(face_value_per_cell)); + + 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_value_per_cell.numberOfSubValues(cell_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per face") + { + CellValuePerFace<int> cell_value_per_face{connectivity}; + REQUIRE(cell_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(cell_value_per_face.numberOfValues() == number_of_values(cell_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + EdgeValuePerFace<int> edge_value_per_face{connectivity}; + REQUIRE(edge_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(edge_value_per_face.numberOfValues() == number_of_values(edge_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerFace<int> node_value_per_face{connectivity}; + REQUIRE(node_value_per_face.numberOfItems() == connectivity.numberOfFaces()); + REQUIRE(node_value_per_face.numberOfValues() == number_of_values(node_value_per_face)); + + 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_value_per_face.numberOfSubValues(face_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per edge") + { + CellValuePerEdge<int> cell_value_per_edge{connectivity}; + REQUIRE(cell_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(cell_value_per_edge.numberOfValues() == number_of_values(cell_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerEdge<int> face_value_per_edge{connectivity}; + REQUIRE(face_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(face_value_per_edge.numberOfValues() == number_of_values(face_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + REQUIRE(node_value_per_edge.numberOfItems() == connectivity.numberOfEdges()); + REQUIRE(node_value_per_edge.numberOfValues() == number_of_values(node_value_per_edge)); + + 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_value_per_edge.numberOfSubValues(edge_id)); + } + REQUIRE(is_correct); + } + } + + SECTION("per node") + { + EdgeValuePerNode<int> edge_value_per_node{connectivity}; + REQUIRE(edge_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(edge_value_per_node.numberOfValues() == number_of_values(edge_value_per_node)); + + 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_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + FaceValuePerNode<int> face_value_per_node{connectivity}; + REQUIRE(face_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(face_value_per_node.numberOfValues() == number_of_values(face_value_per_node)); + + 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_value_per_node.numberOfSubValues(node_id)); + } + REQUIRE(is_correct); + } + + CellValuePerNode<int> cell_value_per_node{connectivity}; + REQUIRE(cell_value_per_node.numberOfItems() == connectivity.numberOfNodes()); + REQUIRE(cell_value_per_node.numberOfValues() == number_of_values(cell_value_per_node)); + + 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_value_per_node.numberOfSubValues(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(); + + EdgeValuePerCell<size_t> edge_values_per_cell{connectivity}; + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_edge = 0; i_edge < edge_values_per_cell.numberOfSubValues(cell_id); ++i_edge) { + edge_values_per_cell(cell_id, i_edge) = value++; + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { + is_same &= (edge_values_per_cell[i] == i); + } + REQUIRE(is_same); + } + + for (size_t i = 0; i < edge_values_per_cell.numberOfValues(); ++i) { + edge_values_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_values_per_cell.numberOfSubValues(cell_id); ++i_edge, ++i) { + is_same &= (edge_values_per_cell(cell_id, i_edge) == 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(); + + CellValuePerFace<size_t> cell_values_per_face{connectivity}; + { + size_t value = 0; + for (FaceId face_id = 0; face_id < connectivity.numberOfFaces(); ++face_id) { + for (size_t i_cell = 0; i_cell < cell_values_per_face.numberOfSubValues(face_id); ++i_cell) { + cell_values_per_face(face_id, i_cell) = value++; + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { + is_same &= (cell_values_per_face[i] == i); + } + REQUIRE(is_same); + } + for (size_t i = 0; i < cell_values_per_face.numberOfValues(); ++i) { + cell_values_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_values_per_face.numberOfSubValues(face_id); ++i_cell, ++i) { + is_same &= (cell_values_per_face(face_id, i_cell) == 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(); + + FaceValuePerNode<size_t> face_values_per_node{connectivity}; + { + size_t value = 0; + for (NodeId node_id = 0; node_id < connectivity.numberOfNodes(); ++node_id) { + for (size_t i_face = 0; i_face < face_values_per_node.numberOfSubValues(node_id); ++i_face) { + face_values_per_node.itemValues(node_id)[i_face] = value++; + } + } + } + { + bool is_same = true; + for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { + is_same &= (face_values_per_node[i] == i); + } + REQUIRE(is_same); + } + + for (size_t i = 0; i < face_values_per_node.numberOfValues(); ++i) { + face_values_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_values_per_node.numberOfSubValues(node_id); ++i_face, ++i) { + is_same &= (face_values_per_node.itemValues(node_id)[i_face] == 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") + { + NodeValuePerCell<size_t> node_value_per_cell{connectivity}; + + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = value++; + } + } + } + + NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } + + REQUIRE(is_same); + } + + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = i_node; + } + } + } + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } + + REQUIRE(not is_same); + } + } + + SECTION("from weak") + { + WeakNodeValuePerCell<size_t> node_value_per_cell{connectivity}; + + { + size_t value = 0; + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = value++; + } + } + } + + NodeValuePerCell<size_t> copy_node_value_per_cell = copy(node_value_per_cell); + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } + + REQUIRE(is_same); + } + + { + for (CellId cell_id = 0; cell_id < connectivity.numberOfCells(); ++cell_id) { + for (size_t i_node = 0; i_node < node_value_per_cell.numberOfSubValues(cell_id); ++i_node) { + node_value_per_cell.itemValues(cell_id)[i_node] = i_node; + } + } + } + + { + bool is_same = true; + for (size_t i = 0; i < copy_node_value_per_cell.numberOfValues(); ++i) { + is_same &= (copy_node_value_per_cell[i] == node_value_per_cell[i]); + } + + REQUIRE(not is_same); + } + } + } + + SECTION("WeakSubItemValuePerItem") + { + const Mesh<Connectivity<2>>& mesh_2d = MeshDataBaseForTests::get().cartesianMesh<2>(); + const Connectivity<2>& connectivity = mesh_2d.connectivity(); + + WeakFaceValuePerCell<int> weak_face_value_per_cell{connectivity}; + + for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { + weak_face_value_per_cell[i] = i; + } + + FaceValuePerCell<const int> face_value_per_cell{weak_face_value_per_cell}; + + REQUIRE(face_value_per_cell.connectivity_ptr() == weak_face_value_per_cell.connectivity_ptr()); + + bool is_same = true; + for (size_t i = 0; i < weak_face_value_per_cell.numberOfValues(); ++i) { + is_same &= (face_value_per_cell[i] == weak_face_value_per_cell[i]); + } + REQUIRE(is_same); + } + +#ifndef NDEBUG + SECTION("error") + { + SECTION("checking for build SubItemValuePerItem") + { + CellValuePerNode<int> cell_value_per_node; + REQUIRE_THROWS_AS(cell_value_per_node[0], AssertError); + REQUIRE_THROWS_AS(cell_value_per_node.itemValues(NodeId{0}), AssertError); + REQUIRE_THROWS_AS(cell_value_per_node(NodeId{0}, 0), AssertError); + REQUIRE_THROWS_AS(cell_value_per_node.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(cell_value_per_node.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(cell_value_per_node.numberOfSubValues(NodeId{0}), AssertError); + + FaceValuePerCell<int> face_value_per_cell; + REQUIRE_THROWS_AS(face_value_per_cell[0], AssertError); + REQUIRE_THROWS_AS(face_value_per_cell.itemValues(CellId{0}), AssertError); + REQUIRE_THROWS_AS(face_value_per_cell(CellId{0}, 0), AssertError); + REQUIRE_THROWS_AS(face_value_per_cell.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(face_value_per_cell.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(face_value_per_cell.numberOfSubValues(CellId{0}), AssertError); + + CellValuePerEdge<int> cell_value_per_edge; + REQUIRE_THROWS_AS(cell_value_per_edge[0], AssertError); + REQUIRE_THROWS_AS(cell_value_per_edge.itemValues(EdgeId{0}), AssertError); + REQUIRE_THROWS_AS(cell_value_per_edge(EdgeId{0}, 0), AssertError); + REQUIRE_THROWS_AS(cell_value_per_edge.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(cell_value_per_edge.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(cell_value_per_edge.numberOfSubValues(EdgeId{0}), AssertError); + + NodeValuePerFace<int> node_value_per_face; + REQUIRE_THROWS_AS(node_value_per_face[0], AssertError); + REQUIRE_THROWS_AS(node_value_per_face.itemValues(FaceId{0}), AssertError); + REQUIRE_THROWS_AS(node_value_per_face(FaceId{0}, 0), AssertError); + REQUIRE_THROWS_AS(node_value_per_face.numberOfValues(), AssertError); + REQUIRE_THROWS_AS(node_value_per_face.numberOfItems(), AssertError); + REQUIRE_THROWS_AS(node_value_per_face.numberOfSubValues(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(); + + CellValuePerFace<int> cell_value_per_face{connectivity}; + { + FaceId invalid_face_id = connectivity.numberOfFaces(); + REQUIRE_THROWS_AS(cell_value_per_face(invalid_face_id, 0), AssertError); + } + if (connectivity.numberOfFaces() > 0) { + FaceId face_id = 0; + const auto& cell_values = cell_value_per_face.itemValues(face_id); + REQUIRE_THROWS_AS(cell_value_per_face(face_id, cell_values.size()), AssertError); + REQUIRE_THROWS_AS(cell_values[cell_values.size()], AssertError); + REQUIRE_THROWS_AS(cell_value_per_face.itemValues(face_id)[cell_values.size()] = 2, AssertError); + } + + FaceValuePerNode<int> face_value_per_node{connectivity}; + { + NodeId invalid_node_id = connectivity.numberOfNodes(); + REQUIRE_THROWS_AS(face_value_per_node(invalid_node_id, 0), AssertError); + } + if (connectivity.numberOfNodes() > 0) { + NodeId node_id = 0; + const auto& face_values = face_value_per_node.itemValues(node_id); + REQUIRE_THROWS_AS(face_value_per_node(node_id, face_values.size()), AssertError); + REQUIRE_THROWS_AS(face_values[face_values.size()], AssertError); + REQUIRE_THROWS_AS(face_value_per_node.itemValues(node_id)[face_values.size()] = 2, AssertError); + } + + EdgeValuePerCell<int> edge_value_per_cell{connectivity}; + { + CellId invalid_cell_id = connectivity.numberOfCells(); + REQUIRE_THROWS_AS(edge_value_per_cell(invalid_cell_id, 0), AssertError); + } + if (connectivity.numberOfCells() > 0) { + CellId cell_id = 0; + const auto& edge_values = edge_value_per_cell.itemValues(cell_id); + REQUIRE_THROWS_AS(edge_value_per_cell(cell_id, edge_values.size()), AssertError); + REQUIRE_THROWS_AS(edge_values[edge_values.size()], AssertError); + REQUIRE_THROWS_AS(edge_value_per_cell.itemValues(cell_id)[edge_values.size()] = 2, AssertError); + } + + NodeValuePerEdge<int> node_value_per_edge{connectivity}; + { + EdgeId invalid_edge_id = connectivity.numberOfEdges(); + REQUIRE_THROWS_AS(node_value_per_edge(invalid_edge_id, 0), AssertError); + } + if (connectivity.numberOfEdges() > 0) { + EdgeId edge_id = 0; + const auto& node_values = node_value_per_edge.itemValues(edge_id); + REQUIRE_THROWS_AS(node_value_per_edge(edge_id, node_values.size()), AssertError); + REQUIRE_THROWS_AS(node_values[node_values.size()], AssertError); + REQUIRE_THROWS_AS(node_value_per_edge.itemValues(edge_id)[node_values.size()] = 2, AssertError); + } + } + } +#endif // NDEBUG +}