#ifndef SUBITEM_VALUE_PER_ITEM_HPP #define SUBITEM_VALUE_PER_ITEM_HPP #include <PugsAssert.hpp> #include <Array.hpp> #include <ItemId.hpp> #include <ConnectivityMatrix.hpp> #include <IConnectivity.hpp> #include <ItemOfItemType.hpp> #include <ItemType.hpp> #include <memory> template <typename DataType, typename ItemOfItem, typename ConnectivityPtr = std::shared_ptr<const IConnectivity>> class SubItemValuePerItem { 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_values; // Allow const std:shared_ptr version to access our data friend SubItemValuePerItem<std::add_const_t<DataType>, ItemOfItem, ConnectivitySharedPtr>; // Allow const std:weak_ptr version to access our data friend SubItemValuePerItem<std::add_const_t<DataType>, ItemOfItem, ConnectivityWeakPtr>; public: using ToShared = SubItemValuePerItem<DataType, ItemOfItem, ConnectivitySharedPtr>; class SubView { public: using data_type = DataType; private: PUGS_RESTRICT DataType* const m_sub_values; const size_t m_size; public: PUGS_INLINE const DataType& operator[](const size_t& i) const noexcept(NO_ASSERT) { Assert(i < m_size); return m_sub_values[i]; } PUGS_FORCEINLINE DataType& operator[](const size_t& i) noexcept(NO_ASSERT) { Assert(i < m_size); return m_sub_values[i]; } PUGS_INLINE size_t size() const noexcept { return m_size; } SubView(const SubView&) = delete; PUGS_INLINE SubView(SubView&&) noexcept = default; PUGS_INLINE SubView(const Array<DataType>& values, const size_t& begin, const size_t& end) noexcept(NO_ASSERT) : m_sub_values(&(values[begin])), m_size(end - begin) { Assert(begin <= end); Assert(end <= values.size()); } }; PUGS_INLINE bool isBuilt() const noexcept { return m_connectivity_ptr.use_count() != 0; } // Following Kokkos logic, these classes are view and const view does allow // changes in data PUGS_FORCEINLINE DataType& operator()(const ItemId& j, const size_t& r) const noexcept(NO_ASSERT) { Assert(this->isBuilt()); return m_values[m_host_row_map(size_t{j}) + r]; } template <typename IndexType> PUGS_FORCEINLINE DataType& operator()(const IndexType& j, const size_t& r) const noexcept(NO_ASSERT) { static_assert(std::is_same_v<IndexType, ItemId>, "SubItemValuePerItem indexed by ItemId"); Assert(this->isBuilt()); return m_values[m_host_row_map(size_t{j}) + r]; } 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 PUGS_FORCEINLINE DataType& operator[](const size_t& i) const noexcept(NO_ASSERT) { Assert(this->isBuilt()); return m_values[i]; } template <typename IndexType> DataType& operator[](const IndexType& i) const noexcept(NO_ASSERT) { static_assert(std::is_same_v<IndexType, size_t>, "Access to SubItemValuePerItem's array must be indexed by " "size_t"); Assert(this->isBuilt()); return m_values[i]; } 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); } PUGS_INLINE size_t numberOfSubValues(const size_t& i_cell) const noexcept(NO_ASSERT) { Assert(this->isBuilt()); return m_host_row_map(i_cell + 1) - m_host_row_map(i_cell); } PUGS_INLINE SubView itemValues(const size_t& i_cell) noexcept(NO_ASSERT) { Assert(this->isBuilt()); const auto& cell_begin = m_host_row_map(i_cell); const auto& cell_end = m_host_row_map(i_cell + 1); return SubView(m_values, cell_begin, cell_end); } // Following Kokkos logic, these classes are view and const view does allow // changes in data PUGS_INLINE SubView itemValues(const size_t& i_cell) const noexcept(NO_ASSERT) { Assert(this->isBuilt()); const auto& cell_begin = m_host_row_map(i_cell); const auto& cell_end = m_host_row_map(i_cell + 1); return SubView(m_values, cell_begin, cell_end); } template <typename DataType2, typename ConnectivityPtr2> PUGS_INLINE SubItemValuePerItem& operator=(const SubItemValuePerItem<DataType2, ItemOfItem, ConnectivityPtr2>& sub_item_value_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 SubItemValuePerItem 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 SubItemValuePerItem of const data to " "SubItemValuePerItem of non-const data"); m_host_row_map = sub_item_value_per_item.m_host_row_map; m_values = sub_item_value_per_item.m_values; if constexpr (std::is_same_v<ConnectivityPtr, ConnectivitySharedPtr> and std::is_same_v<ConnectivityPtr2, ConnectivityWeakPtr>) { m_connectivity_ptr = sub_item_value_per_item.m_connectivity_ptr.lock(); } else { m_connectivity_ptr = sub_item_value_per_item.m_connectivity_ptr; } return *this; } template <typename DataType2, typename ConnectivityPtr2> PUGS_INLINE SubItemValuePerItem( const SubItemValuePerItem<DataType2, ItemOfItem, ConnectivityPtr2>& sub_item_value_per_item) noexcept { this->operator=(sub_item_value_per_item); } SubItemValuePerItem() = default; SubItemValuePerItem(const IConnectivity& connectivity) noexcept : m_connectivity_ptr{connectivity.shared_ptr()} { 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); m_host_row_map = connectivity_matrix.rowsMap(); m_values = Array<std::remove_const_t<DataType>>(connectivity_matrix.numEntries()); } ~SubItemValuePerItem() = default; }; // Item values at nodes template <typename DataType> using NodeValuePerEdge = SubItemValuePerItem<DataType, NodeOfEdge>; template <typename DataType> using NodeValuePerFace = SubItemValuePerItem<DataType, NodeOfFace>; template <typename DataType> using NodeValuePerCell = SubItemValuePerItem<DataType, NodeOfCell>; // Item values at edges template <typename DataType> using EdgeValuePerNode = SubItemValuePerItem<DataType, EdgeOfNode>; template <typename DataType> using EdgeValuePerFace = SubItemValuePerItem<DataType, EdgeOfFace>; template <typename DataType> using EdgeValuePerCell = SubItemValuePerItem<DataType, EdgeOfCell>; // Item values at faces template <typename DataType> using FaceValuePerNode = SubItemValuePerItem<DataType, FaceOfNode>; template <typename DataType> using FaceValuePerEdge = SubItemValuePerItem<DataType, FaceOfEdge>; template <typename DataType> using FaceValuePerCell = SubItemValuePerItem<DataType, FaceOfCell>; // Item values at cells template <typename DataType> using CellValuePerNode = SubItemValuePerItem<DataType, CellOfNode>; template <typename DataType> using CellValuePerEdge = SubItemValuePerItem<DataType, CellOfEdge>; template <typename DataType> using CellValuePerFace = SubItemValuePerItem<DataType, CellOfFace>; // Weak versions: should not be used outside of Connectivity // Item values at nodes template <typename DataType, typename ItemOfItem> using WeakSubItemValuePerItem = SubItemValuePerItem<DataType, ItemOfItem, std::weak_ptr<const IConnectivity>>; template <typename DataType> using WeakNodeValuePerEdge = WeakSubItemValuePerItem<DataType, NodeOfEdge>; template <typename DataType> using WeakNodeValuePerFace = WeakSubItemValuePerItem<DataType, NodeOfFace>; template <typename DataType> using WeakNodeValuePerCell = WeakSubItemValuePerItem<DataType, NodeOfCell>; // Item values at edges template <typename DataType> using WeakEdgeValuePerNode = WeakSubItemValuePerItem<DataType, EdgeOfNode>; template <typename DataType> using WeakEdgeValuePerFace = WeakSubItemValuePerItem<DataType, EdgeOfFace>; template <typename DataType> using WeakEdgeValuePerCell = WeakSubItemValuePerItem<DataType, EdgeOfCell>; // Item values at faces template <typename DataType> using WeakFaceValuePerNode = WeakSubItemValuePerItem<DataType, FaceOfNode>; template <typename DataType> using WeakFaceValuePerEdge = WeakSubItemValuePerItem<DataType, FaceOfEdge>; template <typename DataType> using WeakFaceValuePerCell = WeakSubItemValuePerItem<DataType, FaceOfCell>; // Item values at cells template <typename DataType> using WeakCellValuePerNode = WeakSubItemValuePerItem<DataType, CellOfNode>; template <typename DataType> using WeakCellValuePerEdge = WeakSubItemValuePerItem<DataType, CellOfEdge>; template <typename DataType> using WeakCellValuePerFace = WeakSubItemValuePerItem<DataType, CellOfFace>; #endif // SUBITEM_VALUE_PER_ITEM_HPP