diff --git a/src/mesh/Connectivity.hpp b/src/mesh/Connectivity.hpp index 261437091656cdbbd7111e8f68d75c66ca8b925a..bebb67e014cddf792cd4cd47f462024edb448f6e 100644 --- a/src/mesh/Connectivity.hpp +++ b/src/mesh/Connectivity.hpp @@ -20,7 +20,6 @@ #include <ConnectivityComputer.hpp> #include <vector> -#include <unordered_map> #include <algorithm> #include <CellType.hpp> @@ -214,6 +213,24 @@ class Connectivity final return m_node_number; } + template <ItemType item_type> + PASTIS_INLINE + const auto& number() const + { + if constexpr(item_type == ItemType::cell) { + return m_cell_number; + } else if constexpr(item_type == ItemType::face) { + return m_face_number; + } else if constexpr(item_type == ItemType::edge) { + return m_edge_number; + } else if constexpr(item_type == ItemType::node) { + return m_node_number; + } else { + static_assert(item_type == ItemType::cell, "unknown ItemType"); + return m_cell_number; + } + } + PASTIS_INLINE const auto& cellOwner() const { @@ -242,19 +259,19 @@ class Connectivity final template <ItemType item_type> PASTIS_INLINE - ItemValue<const bool, item_type> isOwned() const + const auto& owner() const { if constexpr(item_type == ItemType::cell) { - return m_cell_is_owned; + return m_cell_owner; } else if constexpr(item_type == ItemType::face) { - return m_face_is_owned; + return m_face_owner; } else if constexpr(item_type == ItemType::edge) { - return m_edge_is_owned; + return m_edge_owner; } else if constexpr(item_type == ItemType::node) { - return m_node_is_owned; + return m_node_owner; } else { static_assert(item_type == ItemType::cell, "unknown ItemType"); - return {}; + return m_cell_owner; } } @@ -284,6 +301,24 @@ class Connectivity final return m_node_is_owned; } + template <ItemType item_type> + PASTIS_INLINE + const auto& isOwned() const + { + if constexpr(item_type == ItemType::cell) { + return m_cell_is_owned; + } else if constexpr(item_type == ItemType::face) { + return m_face_is_owned; + } else if constexpr(item_type == ItemType::edge) { + return m_edge_is_owned; + } else if constexpr(item_type == ItemType::node) { + return m_node_is_owned; + } else { + static_assert(item_type == ItemType::cell, "unknown ItemType"); + return m_cell_is_owned; + } + } + PASTIS_INLINE const bool& isConnectivityMatrixBuilt(const ItemType& item_type_0, const ItemType& item_type_1) const diff --git a/src/mesh/ItemValueSynchronizer.hpp b/src/mesh/ItemValueSynchronizer.hpp index e4189014fdf1ce26b21d493bebe28dcd847ecffc..4a2c9939df80e95183b9d03a25e3b91a2c509455 100644 --- a/src/mesh/ItemValueSynchronizer.hpp +++ b/src/mesh/ItemValueSynchronizer.hpp @@ -4,8 +4,99 @@ #include <ItemValue.hpp> #include <Connectivity.hpp> +#include <unordered_map> + class ItemValueSynchronizer { + template <typename ConnectivityType, + typename DataType, + ItemType item_type, + typename ConnectivityPtr> + PASTIS_INLINE + void _synchronize(const ConnectivityType& connectivity, + ItemValue<DataType, item_type, ConnectivityPtr>& item_value) + { + static_assert(not std::is_abstract_v<ConnectivityType>, + "_synchronize must be called on a concrete connectivity"); + const auto& item_owner = connectivity.template owner<item_type>(); + + using ItemId = ItemIdT<item_type>; + std::vector<std::vector<ItemId>> ghost_items_per_proc(parallel::size()); + for (ItemId item_id=0; item_id<item_value.size(); ++item_id) { + if (const size_t owner = item_owner[item_id]; owner != parallel::rank()) { + ghost_items_per_proc[owner].emplace_back(item_id); + } + } + + Array<unsigned int> local_number_of_requested_values(parallel::size()); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + local_number_of_requested_values[i_rank] = ghost_items_per_proc[i_rank].size(); + } + + Array<unsigned int> local_number_of_values_to_send + = parallel::allToAll(local_number_of_requested_values); + + std::vector<Array<const int>> requested_item_number_list_by_proc(parallel::size()); + const auto& item_number = connectivity.template number<item_type>(); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + const auto& ghost_items = ghost_items_per_proc[i_rank]; + Array<int> item_number_list(ghost_items.size()); + for (size_t i_item = 0; i_item<ghost_items.size(); ++i_item) { + item_number_list[i_item] = item_number[ghost_items[i_item]]; + } + requested_item_number_list_by_proc[i_rank] = item_number_list; + } + + std::vector<Array<int>> to_send_item_number_list_by_proc(parallel::size()); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + to_send_item_number_list_by_proc[i_rank] = Array<int>{local_number_of_values_to_send[i_rank]}; + } + + parallel::exchange(requested_item_number_list_by_proc, to_send_item_number_list_by_proc); + + std::unordered_map<int, ItemId> item_number_to_id_correspondance(connectivity.template numberOf<item_type>()); + for (ItemId item_id=0; item_id<item_number.size(); ++item_id) { + item_number_to_id_correspondance[item_number[item_id]] = item_id; + } + + std::vector<Array<const ItemId>> to_send_item_id_list_by_proc(parallel::size()); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + Array<ItemId> to_send_item_id{local_number_of_values_to_send[i_rank]}; + const Array<int>& to_send_item_number = to_send_item_number_list_by_proc[i_rank]; + for (size_t i=0; i<to_send_item_number.size(); ++i) { + to_send_item_id[i] = item_number_to_id_correspondance[to_send_item_number[i]]; + } + to_send_item_id_list_by_proc[i_rank] = to_send_item_id; + } + + std::vector<Array<const DataType>> to_send_data_by_proc(parallel::size()); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + Array<DataType> to_send_data{local_number_of_values_to_send[i_rank]}; + const Array<const ItemId>& to_send_item_id = to_send_item_id_list_by_proc[i_rank]; + for (size_t i=0; i<to_send_item_id.size(); ++i) { + to_send_data[i] = item_value[to_send_item_id[i]]; + } + to_send_data_by_proc[i_rank] = to_send_data; + } + + std::vector<Array<DataType>> requested_data_list_by_proc(parallel::size()); + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + const auto& ghost_items = ghost_items_per_proc[i_rank]; + requested_data_list_by_proc[i_rank] = Array<DataType>{ghost_items.size()}; + } + + parallel::exchange(to_send_data_by_proc, requested_data_list_by_proc); + + for (size_t i_rank=0; i_rank<parallel::size(); ++i_rank) { + const auto& ghost_items = ghost_items_per_proc[i_rank]; + const auto& requested_data = requested_data_list_by_proc[i_rank]; + for (size_t i=0; i<ghost_items.size(); ++i) { + item_value[ghost_items[i]] = requested_data[i]; + } + requested_data_list_by_proc[i_rank] = Array<DataType>{ghost_items.size()}; + } + } + public: template <typename DataType, ItemType item_type, @@ -13,13 +104,30 @@ class ItemValueSynchronizer PASTIS_INLINE void synchronize(ItemValue<DataType, item_type, ConnectivityPtr>& item_value) { - pout() << "Calling synchronize...\n"; - auto connectivity_ptr = item_value.connectivity_ptr(); - Assert(connectivity_ptr.use_count()>0, "No connectivity is associated to this ItemValue"); - parallel::barrier(); - parallel::Messenger::destroy(); - pout() << __FILE__ << ':' << __LINE__ << ": NIY!\n"; - std::exit(0); + static int cpt=0; + pout() << "Calling synchronize(" << cpt++ << ")...\n"; + + 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; + } + default: { + perr() << __FILE__ << ':' << __LINE__ << ": unexpected dimension\n"; + std::terminate(); + } + } } PASTIS_INLINE diff --git a/src/mesh/ItemValueUtils.hpp b/src/mesh/ItemValueUtils.hpp index cd1110fe78461856f5f82d31ab12789322776d07..771b4e2b675aaac2eab00ba8cb5575f3963e6fbb 100644 --- a/src/mesh/ItemValueUtils.hpp +++ b/src/mesh/ItemValueUtils.hpp @@ -17,8 +17,10 @@ min(const ItemValue<DataType, item_type>& item_value) using data_type = std::remove_const_t<typename ItemValueType::data_type>; using index_type = typename ItemValueType::index_type; - ItemValue<const bool, item_type> is_owned + const auto& is_owned = [&] (const IConnectivity& connectivity) { + Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), + "unexpected connectivity dimension"); switch (connectivity.dimension()) { case 1: { @@ -37,18 +39,19 @@ min(const ItemValue<DataType, item_type>& item_value) break; } default: { - Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), - "unexpected connectivity dimension"); - return ItemValue<const bool, item_type>{}; + perr() << __FILE__ << ':' << __LINE__ << ": unexpected dimension\n"; + std::terminate(); } } } (*item_value.connectivity_ptr()); + using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + class ItemValueMin { private: const ItemValueType& m_item_value; - const ItemValue<const bool, item_type>& m_is_owned; + const IsOwnedType& m_is_owned; public: PASTIS_INLINE @@ -84,7 +87,7 @@ min(const ItemValue<DataType, item_type>& item_value) PASTIS_INLINE ItemValueMin(const ItemValueType& item_value, - const ItemValue<const bool, item_type>& is_owned) + const IsOwnedType& is_owned) : m_item_value(item_value), m_is_owned(is_owned) { @@ -108,8 +111,10 @@ max(const ItemValue<DataType, item_type>& item_value) using data_type = std::remove_const_t<typename ItemValueType::data_type>; using index_type = typename ItemValueType::index_type; - ItemValue<const bool, item_type> is_owned + const auto& is_owned = [&] (const IConnectivity& connectivity) { + Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), + "unexpected connectivity dimension"); switch (connectivity.dimension()) { case 1: { @@ -128,18 +133,19 @@ max(const ItemValue<DataType, item_type>& item_value) break; } default: { - Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), - "unexpected connectivity dimension"); - return ItemValue<const bool, item_type>{}; + perr() << __FILE__ << ':' << __LINE__ << ": unexpected dimension\n"; + std::terminate(); } } } (*item_value.connectivity_ptr()); + using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + class ItemValueMax { private: const ItemValueType& m_item_value; - const ItemValue<const bool, item_type>& m_is_owned; + const IsOwnedType& m_is_owned; public: PASTIS_INLINE @@ -175,7 +181,7 @@ max(const ItemValue<DataType, item_type>& item_value) PASTIS_INLINE ItemValueMax(const ItemValueType& item_value, - const ItemValue<const bool, item_type>& is_owned) + const IsOwnedType& is_owned) : m_item_value(item_value), m_is_owned(is_owned) { @@ -200,8 +206,10 @@ sum(const ItemValue<DataType, item_type>& item_value) using data_type = std::remove_const_t<typename ItemValueType::data_type>; using index_type = typename ItemValueType::index_type; - ItemValue<const bool, item_type> is_owned + const auto& is_owned = [&] (const IConnectivity& connectivity) { + Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), + "unexpected connectivity dimension"); switch (connectivity.dimension()) { case 1: { @@ -220,18 +228,19 @@ sum(const ItemValue<DataType, item_type>& item_value) break; } default: { - Assert((connectivity.dimension()>0) and (connectivity.dimension()<=3), - "unexpected connectivity dimension"); - return ItemValue<const bool, item_type>{}; + perr() << __FILE__ << ':' << __LINE__ << ": unexpected dimension\n"; + std::terminate(); } } } (*item_value.connectivity_ptr()); + using IsOwnedType = std::remove_reference_t<decltype(is_owned)>; + class ItemValueSum { private: const ItemValueType& m_item_value; - const ItemValue<const bool, item_type>& m_is_owned; + const IsOwnedType& m_is_owned; public: PASTIS_INLINE @@ -269,7 +278,7 @@ sum(const ItemValue<DataType, item_type>& item_value) PASTIS_INLINE ItemValueSum(const ItemValueType& item_value, - const ItemValue<const bool, item_type>& is_owned) + const IsOwnedType& is_owned) : m_item_value(item_value), m_is_owned(is_owned) {