Skip to content
Snippets Groups Projects
Commit 0af5c409 authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Add missing synchronization capabilities

In the case of subitems of greater dimension that items,
synchronization was missing for SubItemValuePerItem and
SubItemArrayPerItem.

This has been missing for ages but it not that useful. Actually, it is
more of a completeness functionality.

Related tests have been added.
parent eda39e8c
Branches
Tags
1 merge request!176Add HDF5 support
......@@ -11,9 +11,8 @@
#include <utils/pugs_config.hpp>
#include <iostream>
#include <map>
#include <memory>
#include <unordered_map>
#ifdef PUGS_HAS_MPI
......@@ -23,61 +22,38 @@ class Synchronizer
template <ItemType item_type>
using ExchangeItemTypeInfo = std::vector<Array<const ItemIdT<item_type>>>;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::cell>> m_requested_cell_info;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::cell>> m_provided_cell_info;
using ExchangeItemInfoRepository = std::tuple<std::unique_ptr<ExchangeItemTypeInfo<ItemType::node>>,
std::unique_ptr<ExchangeItemTypeInfo<ItemType::edge>>,
std::unique_ptr<ExchangeItemTypeInfo<ItemType::face>>,
std::unique_ptr<ExchangeItemTypeInfo<ItemType::cell>>>;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::face>> m_requested_face_info;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::face>> m_provided_face_info;
ExchangeItemInfoRepository m_requested_item_info_list;
ExchangeItemInfoRepository m_provided_item_info_list;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::edge>> m_requested_edge_info;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::edge>> m_provided_edge_info;
// here 12 is the maximum number (3d) of sub item of item
// configurations (cell->edge, face->node...)
using ExchangeSubItemPerItemTotalSizeList = std::array<std::unique_ptr<std::vector<size_t>>, 12>;
using SubItemPerItemProvidedList = std::array<std::unique_ptr<std::vector<Array<const size_t>>>, 12>;
using NumberOfSubItemPerItemProvidedList = std::array<std::unique_ptr<std::vector<Array<const size_t>>>, 12>;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::node>> m_requested_node_info;
std::unique_ptr<ExchangeItemTypeInfo<ItemType::node>> m_provided_node_info;
using ExchangeSubItemPerItemSize = std::vector<std::map<std::pair<ItemType, ItemType>, size_t>>;
ExchangeSubItemPerItemSize m_sub_item_per_item_requested_size_list;
ExchangeSubItemPerItemSize m_sub_item_per_item_provided_size_list;
template <ItemType item_type>
PUGS_INLINE constexpr auto&
_getRequestedItemInfo()
{
if constexpr (item_type == ItemType::cell) {
return m_requested_cell_info;
} else if constexpr (item_type == ItemType::face) {
return m_requested_face_info;
} else if constexpr (item_type == ItemType::edge) {
return m_requested_edge_info;
} else if constexpr (item_type == ItemType::node) {
return m_requested_node_info;
}
}
template <ItemType item_type>
PUGS_INLINE constexpr auto&
_getProvidedItemInfo()
{
if constexpr (item_type == ItemType::cell) {
return m_provided_cell_info;
} else if constexpr (item_type == ItemType::face) {
return m_provided_face_info;
} else if constexpr (item_type == ItemType::edge) {
return m_provided_edge_info;
} else if constexpr (item_type == ItemType::node) {
return m_provided_node_info;
}
}
ExchangeSubItemPerItemTotalSizeList m_sub_item_per_item_requested_total_size_list;
ExchangeSubItemPerItemTotalSizeList m_sub_item_per_item_provided_total_size_list;
SubItemPerItemProvidedList m_sub_item_per_item_provided_list;
NumberOfSubItemPerItemProvidedList m_number_of_sub_item_per_item_provided_list;
template <typename ConnectivityType, ItemType item_type>
void
_buildSynchronizeInfo(const ConnectivityType& connectivity)
_buildSynchronizeInfoIfNeeded(const ConnectivityType& connectivity)
{
const auto& item_owner = connectivity.template owner<item_type>();
using ItemId = ItemIdT<item_type>;
auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
auto& p_requested_item_info = std::get<static_cast<int>(item_type)>(m_requested_item_info_list);
auto& p_provided_item_info = std::get<static_cast<int>(item_type)>(m_provided_item_info_list);
Assert(static_cast<bool>(p_provided_item_info) == static_cast<bool>(p_requested_item_info));
if (not p_provided_item_info) {
p_requested_item_info = [&]() {
std::vector<std::vector<ItemId>> requested_item_vector_info(parallel::size());
for (ItemId item_id = 0; item_id < item_owner.numberOfItems(); ++item_id) {
......@@ -108,8 +84,9 @@ class Synchronizer
const auto& requested_item_info_from_rank = requested_item_info[i_rank];
Array<int> item_number_list{requested_item_info_from_rank.size()};
parallel_for(
requested_item_info_from_rank.size(),
PUGS_LAMBDA(size_t i_item) { item_number_list[i_item] = item_number[requested_item_info_from_rank[i_item]]; });
requested_item_info_from_rank.size(), PUGS_LAMBDA(size_t i_item) {
item_number_list[i_item] = item_number[requested_item_info_from_rank[i_item]];
});
requested_item_number_list_by_proc[i_rank] = item_number_list;
}
......@@ -120,45 +97,54 @@ 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;
std::unordered_map<int, ItemId> item_number_to_id_correspondance;
for (ItemId item_id = 0; item_id < item_number.numberOfItems(); ++item_id) {
item_number_to_id_correspondance[item_number[item_id]] = item_id;
}
auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
p_provided_item_info = [&]() {
ExchangeItemTypeInfo<item_type> provided_item_info(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
Array<ItemId> provided_item_id_to_rank{local_number_of_values_to_send[i_rank]};
const Array<int>& provided_item_number_to_rank = provided_item_number_list_by_rank[i_rank];
for (size_t i = 0; i < provided_item_number_to_rank.size(); ++i) {
provided_item_id_to_rank[i] = item_number_to_id_correspondance.find(provided_item_number_to_rank[i])->second;
provided_item_id_to_rank[i] =
item_number_to_id_correspondance.find(provided_item_number_to_rank[i])->second;
}
provided_item_info[i_rank] = provided_item_id_to_rank;
}
return std::make_unique<ExchangeItemTypeInfo<item_type>>(provided_item_info);
}();
m_sub_item_per_item_provided_size_list.resize(parallel::size());
m_sub_item_per_item_requested_size_list.resize(parallel::size());
}
}
template <ItemType item_type, ItemType sub_item_type, size_t Dimension>
PUGS_INLINE size_t
_getSubItemPerItemRequestedSize(const Connectivity<Dimension>& connectivity, const size_t i_rank)
template <typename ConnectivityType, ItemType item_type>
PUGS_INLINE constexpr auto&
_getRequestedItemInfo(const ConnectivityType& connectivity)
{
Assert(m_sub_item_per_item_requested_size_list.size() == parallel::size());
this->_buildSynchronizeInfoIfNeeded<ConnectivityType, item_type>(connectivity);
return *std::get<static_cast<int>(item_type)>(m_requested_item_info_list);
}
auto key = std::make_pair(item_type, sub_item_type);
if (auto i_size_list = m_sub_item_per_item_requested_size_list[i_rank].find(key);
i_size_list != m_sub_item_per_item_requested_size_list[i_rank].end()) {
return i_size_list->second;
} else {
const auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
template <typename ConnectivityType, ItemType item_type>
PUGS_INLINE constexpr auto&
_getProvidedItemInfo(const ConnectivityType& connectivity)
{
this->_buildSynchronizeInfoIfNeeded<ConnectivityType, item_type>(connectivity);
return *std::get<static_cast<int>(item_type)>(m_provided_item_info_list);
}
Assert(static_cast<bool>(p_requested_item_info) == true,
"this function should be called after calculation of exchange info");
const auto& requested_item_info_from_rank = (*p_requested_item_info)[i_rank];
template <ItemType item_type, ItemType sub_item_type, typename ConnectivityType>
PUGS_INLINE const std::vector<size_t>&
_getSubItemPerItemRequestedTotalSize(const ConnectivityType& connectivity)
{
auto& p_sub_item_per_item_requested_total_size =
m_sub_item_per_item_requested_total_size_list[item_of_item_type_index<sub_item_type, item_type>];
if (not p_sub_item_per_item_requested_total_size) {
std::vector<size_t> sub_item_per_item_requested_total_size(parallel::size());
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
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& item_to_item_matrix = connectivity.template getItemToItemMatrix<item_type, sub_item_type>();
......@@ -167,27 +153,31 @@ class Synchronizer
count += item_to_item_matrix[requested_item_info_from_rank[i]].size();
}
m_sub_item_per_item_requested_size_list[i_rank][key] = count;
return count;
sub_item_per_item_requested_total_size[i_rank] = count;
}
p_sub_item_per_item_requested_total_size =
std::make_unique<std::vector<size_t>>(std::move(sub_item_per_item_requested_total_size));
}
return (*p_sub_item_per_item_requested_total_size);
}
template <ItemType item_type, ItemType sub_item_type, size_t Dimension>
PUGS_INLINE size_t
_getSubItemPerItemProvidedSize(const Connectivity<Dimension>& connectivity, const size_t i_rank)
template <ItemType item_type, ItemType sub_item_type, typename ConnectivityType>
PUGS_INLINE const std::vector<size_t>&
_getSubItemPerItemProvidedTotalSize(const ConnectivityType& connectivity)
{
Assert(m_sub_item_per_item_provided_size_list.size() == parallel::size());
static_assert(item_type != sub_item_type);
auto key = std::make_pair(item_type, sub_item_type);
if (auto i_size_list = m_sub_item_per_item_provided_size_list[i_rank].find(key);
i_size_list != m_sub_item_per_item_provided_size_list[i_rank].end()) {
return i_size_list->second;
} else {
const auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
auto& p_sub_item_per_item_provided_total_size =
m_sub_item_per_item_provided_total_size_list[item_of_item_type_index<sub_item_type, item_type>];
Assert(static_cast<bool>(p_provided_item_info) == true,
"this function should be called after calculation of exchange info");
const auto& provided_item_info_from_rank = (*p_provided_item_info)[i_rank];
if (not p_sub_item_per_item_provided_total_size) {
if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(sub_item_type)) {
std::vector<size_t> sub_item_per_item_provided_total_size(parallel::size());
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
const auto& provided_item_info_from_rank = provided_item_info[i_rank];
const auto& item_to_item_matrix = connectivity.template getItemToItemMatrix<item_type, sub_item_type>();
......@@ -196,32 +186,212 @@ class Synchronizer
count += item_to_item_matrix[provided_item_info_from_rank[i]].size();
}
m_sub_item_per_item_provided_size_list[i_rank][key] = count;
return count;
sub_item_per_item_provided_total_size[i_rank] = count;
}
p_sub_item_per_item_provided_total_size =
std::make_unique<std::vector<size_t>>(std::move(sub_item_per_item_provided_total_size));
} else {
std::vector<size_t> sub_item_per_item_provided_total_size(parallel::size());
const auto& sub_item_required_total_size =
_getSubItemPerItemRequestedTotalSize<item_type, sub_item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<size_t>> sub_item_required_total_size_exchange(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
Assert((sub_item_required_total_size[i_rank] == 0) xor (requested_item_info[i_rank].size() > 0),
"unexpected sub_item size info");
if (requested_item_info[i_rank].size() > 0) {
Array<size_t> size_0d_array(1);
size_0d_array[0] = sub_item_required_total_size[i_rank];
sub_item_required_total_size_exchange[i_rank] = size_0d_array;
}
}
template <typename ConnectivityType, typename DataType, ItemType item_type, typename ConnectivityPtr>
PUGS_INLINE void
_synchronize(const ConnectivityType& connectivity, ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<size_t>> sub_item_provided_total_size_exchange(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (provided_item_info[i_rank].size() > 0) {
Array<size_t> size_0d_array(1);
sub_item_provided_total_size_exchange[i_rank] = size_0d_array;
}
}
parallel::exchange(sub_item_required_total_size_exchange, sub_item_provided_total_size_exchange);
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (sub_item_provided_total_size_exchange[i_rank].size() > 0) {
sub_item_per_item_provided_total_size[i_rank] = sub_item_provided_total_size_exchange[i_rank][0];
}
}
p_sub_item_per_item_provided_total_size =
std::make_unique<std::vector<size_t>>(std::move(sub_item_per_item_provided_total_size));
}
}
return (*p_sub_item_per_item_provided_total_size);
}
template <ItemType item_type, ItemType sub_item_type, typename ConnectivityType>
PUGS_INLINE const std::vector<Array<const size_t>>&
_getNumberOfSubItemPerItemProvidedList(const ConnectivityType& connectivity)
{
static_assert(not std::is_abstract_v<ConnectivityType>, "_synchronize must be called on a concrete connectivity");
static_assert(ItemTypeId<ConnectivityType::Dimension>::dimension(sub_item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(item_type),
"should not be called if dimension of sub item is lower than item");
auto& p_number_of_sub_item_per_item_provided_list =
m_number_of_sub_item_per_item_provided_list[item_of_item_type_index<sub_item_type, item_type>];
if (not p_number_of_sub_item_per_item_provided_list) {
using ItemId = ItemIdT<item_type>;
const auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
const auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
const auto& item_to_item_matrix = connectivity.template getItemToItemMatrix<item_type, sub_item_type>();
const auto number_of_sub_item = connectivity.template number<sub_item_type>();
Assert(static_cast<bool>(p_provided_item_info) == static_cast<bool>(p_requested_item_info));
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
if (not p_provided_item_info) {
this->_buildSynchronizeInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<size_t>> number_of_sub_item_per_item_required_exchange(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];
if (requested_item_info_from_rank.size() > 0) {
Array<size_t> number_of_sub_item_per_item(requested_item_info_from_rank.size());
size_t count = 0;
for (size_t i_item = 0; i_item < requested_item_info_from_rank.size(); ++i_item) {
const ItemId item_id = requested_item_info_from_rank[i_item];
number_of_sub_item_per_item[count++] = item_to_item_matrix[item_id].size();
}
number_of_sub_item_per_item_required_exchange[i_rank] = number_of_sub_item_per_item;
}
}
const auto& provided_item_info = *p_provided_item_info;
const auto& requested_item_info = *p_requested_item_info;
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<size_t>> number_of_sub_item_per_item_provided_exchange(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (provided_item_info[i_rank].size() > 0) {
number_of_sub_item_per_item_provided_exchange[i_rank] = Array<size_t>{provided_item_info[i_rank].size()};
}
}
Assert(requested_item_info.size() == provided_item_info.size());
parallel::exchange(number_of_sub_item_per_item_required_exchange, number_of_sub_item_per_item_provided_exchange);
std::vector<Array<const size_t>> number_of_sub_item_per_item_provided_list(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
number_of_sub_item_per_item_provided_list[i_rank] = number_of_sub_item_per_item_provided_exchange[i_rank];
}
p_number_of_sub_item_per_item_provided_list =
std::make_unique<std::vector<Array<const size_t>>>(std::move(number_of_sub_item_per_item_provided_list));
}
return *p_number_of_sub_item_per_item_provided_list;
}
template <ItemType item_type, ItemType sub_item_type, typename ConnectivityType>
PUGS_INLINE const std::vector<Array<const size_t>>&
_getSubItemPerItemProvidedList(const ConnectivityType& connectivity)
{
static_assert(ItemTypeId<ConnectivityType::Dimension>::dimension(sub_item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(item_type),
"should not be called if dimension of sub item is lower than item");
auto& p_sub_item_per_item_provided_list =
m_sub_item_per_item_provided_list[item_of_item_type_index<sub_item_type, item_type>];
if (not p_sub_item_per_item_provided_list) {
using ItemId = ItemIdT<item_type>;
const auto& item_to_item_matrix = connectivity.template getItemToItemMatrix<item_type, sub_item_type>();
const auto number_of_sub_item = connectivity.template number<sub_item_type>();
const auto& sub_item_required_size = _getSubItemPerItemRequestedTotalSize<item_type, sub_item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<int>> sub_item_per_item_required_numbers_exchange(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
Assert((sub_item_required_size[i_rank] == 0) xor (requested_item_info[i_rank].size() > 0),
"unexpected sub_item size info");
if (requested_item_info[i_rank].size() > 0) {
Array<int> sub_item_numbers(sub_item_required_size[i_rank]);
size_t count = 0;
const auto& requested_item_info_from_rank = requested_item_info[i_rank];
for (size_t i_item = 0; i_item < requested_item_info_from_rank.size(); ++i_item) {
const ItemId item_id = requested_item_info_from_rank[i_item];
auto item_sub_items = item_to_item_matrix[item_id];
for (size_t i_sub_item = 0; i_sub_item < item_sub_items.size(); ++i_sub_item) {
sub_item_numbers[count++] = number_of_sub_item[item_sub_items[i_sub_item]];
}
}
Assert(count == sub_item_numbers.size());
sub_item_per_item_required_numbers_exchange[i_rank] = sub_item_numbers;
}
}
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& sub_item_provided_size = _getSubItemPerItemProvidedTotalSize<item_type, sub_item_type>(connectivity);
std::vector<Array<int>> sub_item_per_item_provided_numbers_exchange(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (provided_item_info[i_rank].size() > 0) {
sub_item_per_item_provided_numbers_exchange[i_rank] = Array<int>{sub_item_provided_size[i_rank]};
}
}
parallel::exchange(sub_item_per_item_required_numbers_exchange, sub_item_per_item_provided_numbers_exchange);
const auto& number_of_sub_item_per_item_provided_list =
this->_getNumberOfSubItemPerItemProvidedList<item_type, sub_item_type>(connectivity);
std::vector<Array<const size_t>> sub_item_per_item_provided_list(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
if (provided_item_info[i_rank].size() > 0) {
const auto& sub_item_numbers = sub_item_per_item_provided_numbers_exchange[i_rank];
const auto& number_of_sub_item_per_item = number_of_sub_item_per_item_provided_list[i_rank];
Array<size_t> sub_item_list{sub_item_provided_size[i_rank]};
size_t count = 0;
const auto& provided_item_info_to_rank = provided_item_info[i_rank];
for (size_t i_item = 0; i_item < provided_item_info_to_rank.size(); ++i_item) {
const ItemId item_id = provided_item_info_to_rank[i_item];
auto item_sub_items = item_to_item_matrix[item_id];
bool found = false;
for (size_t i_sub_item = 0, i_requied_sub_item = 0; i_sub_item < item_sub_items.size(); ++i_sub_item) {
found = false;
int number = sub_item_numbers[count];
if (number == number_of_sub_item[item_sub_items[i_sub_item]]) {
found = true;
sub_item_list[count] = i_sub_item;
i_requied_sub_item++;
count++;
if (i_requied_sub_item == number_of_sub_item_per_item[i_item]) {
break;
}
}
}
Assert(found, "something wierd occured");
}
Assert(count == sub_item_list.size());
sub_item_per_item_provided_list[i_rank] = sub_item_list;
}
}
p_sub_item_per_item_provided_list =
std::make_unique<std::vector<Array<const size_t>>>(std::move(sub_item_per_item_provided_list));
}
return (*p_sub_item_per_item_provided_list);
}
template <typename ConnectivityType, typename DataType, ItemType item_type, typename ConnectivityPtr>
PUGS_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");
using ItemId = ItemIdT<item_type>;
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
std::vector<Array<const DataType>> provided_data_list(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
......@@ -258,20 +428,10 @@ class Synchronizer
using ItemId = ItemIdT<item_type>;
const auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
const auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
Assert(static_cast<bool>(p_provided_item_info) == static_cast<bool>(p_requested_item_info));
if (not p_provided_item_info) {
this->_buildSynchronizeInfo<ConnectivityType, item_type>(connectivity);
}
const auto& provided_item_info = *p_provided_item_info;
const auto& requested_item_info = *p_requested_item_info;
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
Assert(requested_item_info.size() == provided_item_info.size());
const size_t size_of_arrays = item_array.sizeOfArrays();
std::vector<Array<const DataType>> provided_data_list(parallel::size());
......@@ -316,34 +476,27 @@ class Synchronizer
_synchronize(const ConnectivityType& connectivity,
SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_value_per_item)
{
static_assert(ItemOfItem::item_type != ItemOfItem::sub_item_type);
static_assert(not std::is_abstract_v<ConnectivityType>, "_synchronize must be called on a concrete connectivity");
if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
constexpr ItemType item_type = ItemOfItem::item_type;
constexpr ItemType sub_item_type = ItemOfItem::sub_item_type;
using ItemId = ItemIdT<item_type>;
const auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
const auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
Assert(static_cast<bool>(p_provided_item_info) == static_cast<bool>(p_requested_item_info));
if (not p_provided_item_info) {
this->_buildSynchronizeInfo<ConnectivityType, item_type>(connectivity);
}
const auto& provided_item_info = *p_provided_item_info;
const auto& requested_item_info = *p_requested_item_info;
Assert(requested_item_info.size() == provided_item_info.size());
const auto& sub_item_per_item_provided_size =
_getSubItemPerItemProvidedTotalSize<item_type, sub_item_type>(connectivity);
std::vector<Array<const DataType>> provided_data_list(parallel::size());
if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
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];
const size_t send_size = _getSubItemPerItemProvidedSize<item_type, sub_item_type>(connectivity, i_rank);
Array<DataType> provided_data{send_size};
Array<DataType> provided_data{sub_item_per_item_provided_size[i_rank]};
size_t index = 0;
for (size_t i = 0; i < provided_item_info_to_rank.size(); ++i) {
const ItemId item_id = provided_item_info_to_rank[i];
......@@ -354,14 +507,42 @@ class Synchronizer
}
provided_data_list[i_rank] = provided_data;
}
} else if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) <
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
const auto& number_of_sub_item_per_item_provided_list =
this->_getNumberOfSubItemPerItemProvidedList<item_type, sub_item_type>(connectivity);
const auto& sub_item_per_item_provided_list =
this->_getSubItemPerItemProvidedList<item_type, sub_item_type>(connectivity);
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];
const Array<const size_t>& sub_item_per_item_provided_list_to_rank = sub_item_per_item_provided_list[i_rank];
const Array<const size_t>& number_of_sub_item_per_item_provided_list_to_rank =
number_of_sub_item_per_item_provided_list[i_rank];
Array<DataType> provided_data{sub_item_per_item_provided_size[i_rank]};
size_t index = 0;
for (size_t i = 0; i < provided_item_info_to_rank.size(); ++i) {
const ItemId item_id = provided_item_info_to_rank[i];
const auto item_values = sub_item_value_per_item.itemArray(item_id);
for (size_t j = 0; j < number_of_sub_item_per_item_provided_list_to_rank[i]; ++j, ++index) {
provided_data[index] = item_values[sub_item_per_item_provided_list_to_rank[index]];
}
}
provided_data_list[i_rank] = provided_data;
}
}
const auto& sub_item_per_item_requested_size =
_getSubItemPerItemRequestedTotalSize<item_type, sub_item_type>(connectivity);
std::vector<Array<DataType>> requested_data_list(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
const size_t recv_size = _getSubItemPerItemRequestedSize<item_type, sub_item_type>(connectivity, i_rank);
requested_data_list[i_rank] = Array<DataType>{recv_size};
requested_data_list[i_rank] = Array<DataType>{sub_item_per_item_requested_size[i_rank]};
}
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];
......@@ -369,18 +550,12 @@ class Synchronizer
size_t index = 0;
for (size_t i = 0; i < requested_item_info_from_rank.size(); ++i) {
const ItemId item_id = requested_item_info_from_rank[i];
const auto item_values = sub_item_value_per_item.itemArray(item_id);
for (size_t j = 0; j < item_values.size(); ++j) {
item_values[j] = requested_data[index++];
const auto sub_item_values = sub_item_value_per_item.itemArray(item_id);
for (size_t j = 0; j < sub_item_values.size(); ++j) {
sub_item_values[j] = requested_data[index++];
}
}
}
} else {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
}
template <typename ConnectivityType, typename DataType, typename ItemOfItem, typename ConnectivityPtr>
......@@ -388,34 +563,28 @@ class Synchronizer
_synchronize(const ConnectivityType& connectivity,
SubItemArrayPerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_array_per_item)
{
static_assert(ItemOfItem::item_type != ItemOfItem::sub_item_type);
static_assert(not std::is_abstract_v<ConnectivityType>, "_synchronize must be called on a concrete connectivity");
if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
constexpr ItemType item_type = ItemOfItem::item_type;
constexpr ItemType sub_item_type = ItemOfItem::sub_item_type;
using ItemId = ItemIdT<item_type>;
const auto& p_provided_item_info = this->_getProvidedItemInfo<item_type>();
const auto& p_requested_item_info = this->_getRequestedItemInfo<item_type>();
Assert(static_cast<bool>(p_provided_item_info) == static_cast<bool>(p_requested_item_info));
if (not p_provided_item_info) {
this->_buildSynchronizeInfo<ConnectivityType, item_type>(connectivity);
}
const auto& provided_item_info = this->_getProvidedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& requested_item_info = this->_getRequestedItemInfo<ConnectivityType, item_type>(connectivity);
const auto& provided_item_info = *p_provided_item_info;
const auto& requested_item_info = *p_requested_item_info;
Assert(requested_item_info.size() == provided_item_info.size());
const auto& sub_item_per_item_provided_size =
_getSubItemPerItemProvidedTotalSize<item_type, sub_item_type>(connectivity);
std::vector<Array<const DataType>> provided_data_list(parallel::size());
if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) >
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
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];
const size_t send_size = _getSubItemPerItemProvidedSize<item_type, sub_item_type>(connectivity, i_rank);
Array<DataType> provided_data{send_size * sub_item_array_per_item.sizeOfArrays()};
Array<DataType> provided_data{sub_item_per_item_provided_size[i_rank] * sub_item_array_per_item.sizeOfArrays()};
size_t index = 0;
for (size_t i = 0; i < provided_item_info_to_rank.size(); ++i) {
const ItemId item_id = provided_item_info_to_rank[i];
......@@ -429,11 +598,44 @@ class Synchronizer
}
provided_data_list[i_rank] = provided_data;
}
} else if constexpr (ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::item_type) <
ItemTypeId<ConnectivityType::Dimension>::dimension(ItemOfItem::sub_item_type)) {
const auto& number_of_sub_item_per_item_provided_list =
this->_getNumberOfSubItemPerItemProvidedList<item_type, sub_item_type>(connectivity);
const auto& sub_item_per_item_provided_list =
this->_getSubItemPerItemProvidedList<item_type, sub_item_type>(connectivity);
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];
const Array<const size_t>& sub_item_per_item_provided_list_to_rank = sub_item_per_item_provided_list[i_rank];
const Array<const size_t>& number_of_sub_item_per_item_provided_list_to_rank =
number_of_sub_item_per_item_provided_list[i_rank];
Array<DataType> provided_data{sub_item_per_item_provided_size[i_rank] * sub_item_array_per_item.sizeOfArrays()};
size_t index = 0;
for (size_t i = 0; i < provided_item_info_to_rank.size(); ++i) {
const ItemId item_id = provided_item_info_to_rank[i];
const auto item_table = sub_item_array_per_item.itemTable(item_id);
for (size_t j = 0; j < number_of_sub_item_per_item_provided_list_to_rank[i]; ++j, ++index) {
Assert(item_table.numberOfColumns() == sub_item_array_per_item.sizeOfArrays());
for (size_t k = 0; k < sub_item_array_per_item.sizeOfArrays(); ++k) {
provided_data[sub_item_array_per_item.sizeOfArrays() * index + k] =
item_table(sub_item_per_item_provided_list_to_rank[index], k);
}
}
}
Assert(index == sub_item_per_item_provided_list_to_rank.size());
provided_data_list[i_rank] = provided_data;
}
}
const auto& sub_item_per_item_requested_size =
_getSubItemPerItemRequestedTotalSize<item_type, sub_item_type>(connectivity);
std::vector<Array<DataType>> requested_data_list(parallel::size());
for (size_t i_rank = 0; i_rank < parallel::size(); ++i_rank) {
const size_t recv_size = _getSubItemPerItemRequestedSize<item_type, sub_item_type>(connectivity, i_rank);
requested_data_list[i_rank] = Array<DataType>{recv_size * sub_item_array_per_item.sizeOfArrays()};
requested_data_list[i_rank] =
Array<DataType>{sub_item_per_item_requested_size[i_rank] * sub_item_array_per_item.sizeOfArrays()};
}
parallel::exchange(provided_data_list, requested_data_list);
......@@ -453,12 +655,6 @@ class Synchronizer
}
}
}
} else {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
}
public:
......@@ -466,6 +662,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemValue of const data");
Assert(item_value.connectivity_ptr().use_count() > 0, "No connectivity is associated to this ItemValue");
const IConnectivity& connectivity = *item_value.connectivity_ptr();
......@@ -494,6 +691,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(ItemArray<DataType, item_type, ConnectivityPtr>& item_array)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemArray of const data");
Assert(item_array.connectivity_ptr().use_count() > 0, "No connectivity is associated to this ItemArray");
const IConnectivity& connectivity = *item_array.connectivity_ptr();
......@@ -522,6 +720,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_value_per_item)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize SubItemValuePerItem of const data");
Assert(sub_item_value_per_item.connectivity_ptr().use_count() > 0,
"No connectivity is associated to this SubItemValuePerItem");
......@@ -552,6 +751,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(SubItemArrayPerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_value_per_item)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize SubItemArrayPerItem of const data");
Assert(sub_item_value_per_item.connectivity_ptr().use_count() > 0,
"No connectivity is associated to this SubItemValuePerItem");
......@@ -600,6 +800,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemValue of const data");
Assert(item_value.connectivity_ptr().use_count() > 0, "No connectivity is associated to this ItemValue");
}
......@@ -607,6 +808,7 @@ class Synchronizer
PUGS_INLINE void
synchronize(ItemArray<DataType, item_type, ConnectivityPtr>& item_value)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize ItemArray of const data");
Assert(item_value.connectivity_ptr().use_count() > 0, "No connectivity is associated to this ItemValue");
}
......@@ -614,96 +816,18 @@ class Synchronizer
PUGS_INLINE void
synchronize(SubItemValuePerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_value_per_item)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize SubItemValuePerItem of const data");
Assert(sub_item_value_per_item.connectivity_ptr().use_count() > 0,
"No connectivity is associated to this SubItemValuePerItem");
const IConnectivity& connectivity = *sub_item_value_per_item.connectivity_ptr();
switch (connectivity.dimension()) {
case 1: {
if constexpr (ItemTypeId<1>::dimension(ItemOfItem::item_type) <=
ItemTypeId<1>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
case 2: {
if constexpr (ItemTypeId<2>::dimension(ItemOfItem::item_type) <=
ItemTypeId<2>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
case 3: {
if constexpr (ItemTypeId<3>::dimension(ItemOfItem::item_type) <=
ItemTypeId<3>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
// LCOV_EXCL_START
default: {
throw UnexpectedError("unexpected dimension");
}
// LCOV_EXCL_STOP
}
}
template <typename DataType, typename ItemOfItem, typename ConnectivityPtr>
PUGS_INLINE void
synchronize(SubItemArrayPerItem<DataType, ItemOfItem, ConnectivityPtr>& sub_item_array_per_item)
{
static_assert(not std::is_const_v<DataType>, "cannot synchronize SubItemArrayPerItem of const data");
Assert(sub_item_array_per_item.connectivity_ptr().use_count() > 0,
"No connectivity is associated to this SubItemArrayPerItem");
const IConnectivity& connectivity = *sub_item_array_per_item.connectivity_ptr();
switch (connectivity.dimension()) {
case 1: {
if constexpr (ItemTypeId<1>::dimension(ItemOfItem::item_type) <=
ItemTypeId<1>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
case 2: {
if constexpr (ItemTypeId<2>::dimension(ItemOfItem::item_type) <=
ItemTypeId<2>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
case 3: {
if constexpr (ItemTypeId<3>::dimension(ItemOfItem::item_type) <=
ItemTypeId<3>::dimension(ItemOfItem::sub_item_type)) {
std::ostringstream os;
os << "synchronization requires sub-item type (" << itemName(ItemOfItem::sub_item_type)
<< ") to be of lower dimension than item (" << itemName(ItemOfItem::item_type) << ")";
throw UnexpectedError(os.str());
}
break;
}
// LCOV_EXCL_START
default: {
throw UnexpectedError("unexpected dimension");
}
// LCOV_EXCL_STOP
}
}
Synchronizer(const Synchronizer&) = delete;
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment