702 namespace ComputeIndexOwner
704 class FlexibleIndexStorage
707 using index_type =
unsigned int;
711 FlexibleIndexStorage(
const bool use_vector =
true);
714 reinit(
const bool use_vector,
715 const bool index_range_contiguous,
716 const std::size_t size);
719 fill(
const std::size_t start,
720 const std::size_t end,
721 const index_type &value);
724 operator[](
const std::size_t index);
727 operator[](
const std::size_t index)
const;
730 entry_has_been_set(
const std::size_t index)
const;
814 std::pair<types::global_dof_index, types::global_dof_index>
855 get_index_offset(
const unsigned int rank);
863 get_owning_rank_index(
const unsigned int rank_in_owned_indices,
864 const unsigned int guess = 0);
883 class ConsensusAlgorithmsPayload
886 using RequestType = std::vector<
887 std::pair<types::global_dof_index, types::global_dof_index>>;
888 using AnswerType = std::vector<unsigned int>;
893 ConsensusAlgorithmsPayload(
const IndexSet &owned_indices,
896 std::vector<unsigned int> &owning_ranks,
897 const bool track_index_requesters =
false);
955 std::vector<std::vector<
956 std::pair<
unsigned int,
966 std::map<
unsigned int,
967 std::pair<std::vector<types::global_dof_index>,
968 std::vector<unsigned int>>>
974 std::vector<unsigned int>
981 std::pair<types::global_dof_index, types::global_dof_index>>
982 create_request(
const unsigned int other_rank);
987 std::vector<unsigned int>
989 const unsigned int other_rank,
998 process_answer(
const unsigned int other_rank,
999 const std::vector<unsigned int> &recv_buffer);
1016 std::map<unsigned int, IndexSet>
1034 append_index_origin(
1036 const unsigned int rank_of_request,
1037 const unsigned int rank_of_owner,
1038 unsigned int &owner_index_guess);
1053 Dictionary::get_index_offset(
const unsigned int rank)
1065 Dictionary::get_owning_rank_index(
1066 const unsigned int rank_in_owned_indices,
1067 const unsigned int guess)
1076 rank_in_owned_indices);
1084 const FlexibleIndexStorage::index_type
1085 FlexibleIndexStorage::invalid_index_value;
1089 FlexibleIndexStorage::FlexibleIndexStorage(
const bool use_vector)
1097 FlexibleIndexStorage::reinit(
const bool use_vector,
1098 const bool index_range_contiguous,
1099 const std::size_t
size)
1116 FlexibleIndexStorage::fill(
1117 const std::size_t start,
1118 const std::size_t end,
1119 const FlexibleIndexStorage::index_type &value)
1126 if (
data.empty() && end > start)
1137 std::fill(
data.begin() + start,
data.begin() + end, value);
1145 std::fill(
data.begin() + start,
data.begin() + end, value);
1150 for (
auto i = start; i <
end; ++i)
1157 FlexibleIndexStorage::index_type &
1158 FlexibleIndexStorage::operator[](
const std::size_t index)
1177 FlexibleIndexStorage::entry_has_been_set(
const std::size_t index)
const
1204 std::map<
unsigned int,
1209 const auto owned_indices_size_actual =
1214 owned_indices_size_actual ==
1227 std::pair<types::global_dof_index, types::global_dof_index>
1228 index_range(*interval->begin(), interval->last() + 1);
1232 while (index_range.first != index_range.second)
1234 Assert(index_range.first < index_range.second,
1237 const unsigned int owner =
1238 dof_to_dict_rank(index_range.first);
1243 std::min(get_index_offset(owner + 1), index_range.second);
1264 dic_local_received += next_index - index_range.first;
1269 buffers[owner].emplace_back(index_range.first, next_index);
1271 index_range.first = next_index;
1275#ifdef DEAL_II_WITH_MPI
1277 std::vector<MPI_Request> request;
1291 static CollectiveMutex mutex;
1292 CollectiveMutex::ScopedLock lock(mutex,
comm);
1299 for (
const auto &rank_pair : buffers)
1301 request.push_back(MPI_Request());
1302 const int ierr = MPI_Isend(rank_pair.second.data(),
1303 rank_pair.second.size() * 2,
1313 while (this->locally_owned_size != dic_local_received)
1317 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1322 ierr = MPI_Get_count(&status,
1327 const auto other_rank = status.MPI_SOURCE;
1333 std::pair<types::global_dof_index, types::global_dof_index>>
1334 buffer(number_amount / 2);
1335 ierr = MPI_Recv(buffer.data(),
1344 for (
auto interval : buffer)
1348 i < interval.second;
1366 dic_local_received += interval.second - interval.first;
1378 using RequestType = std::vector<
1379 std::pair<types::global_dof_index, types::global_dof_index>>;
1381 ConsensusAlgorithms::selector<RequestType>(
1384 std::vector<unsigned int> targets;
1385 targets.reserve(buffers.size());
1386 for (
const auto &rank_pair : buffers)
1387 targets.emplace_back(rank_pair.
first);
1393 [&buffers](
const unsigned int target_rank) -> RequestType {
1394 return buffers.at(target_rank);
1398 [&](
const unsigned int source_rank,
1399 const RequestType &request) ->
void {
1401 for (
auto interval : request)
1405 i < interval.second;
1411 "Multiple processes seem to own the same global index. "
1412 "A possible reason is that the sets of locally owned "
1413 "indices are not distinct."));
1414 Assert(interval.first < interval.second,
1420 "The specified interval is not handled by the current process."));
1443 if (request.size() > 0)
1445 const int ierr = MPI_Waitall(request.size(),
1447 MPI_STATUSES_IGNORE);
1454 (void)dic_local_received;
1485 ConsensusAlgorithmsPayload::ConsensusAlgorithmsPayload(
1504 std::vector<unsigned int>
1505 ConsensusAlgorithmsPayload::compute_targets()
1507 std::vector<unsigned int> targets;
1510 unsigned int index = 0;
1511 unsigned int owner_index_guess = 0;
1514 unsigned int other_rank =
dict.dof_to_dict_rank(i);
1518 dict.actually_owning_ranks[i -
dict.local_range.first];
1520 append_index_origin(i -
dict.local_range.first,
1527 if (targets.empty() || targets.back() != other_rank)
1528 targets.push_back(other_rank);
1530 indices.first.push_back(i);
1531 indices.second.push_back(index);
1544 std::vector<std::pair<types::global_dof_index, types::global_dof_index>>
1545 ConsensusAlgorithmsPayload::create_request(
1546 const unsigned int other_rank)
1549 std::pair<types::global_dof_index, types::global_dof_index>>
1555 is.add_indices(indices_i.begin(), indices_i.end());
1558 for (
auto interval = is.begin_intervals();
1559 interval != is.end_intervals();
1561 send_buffer.emplace_back(*interval->begin(), interval->last() + 1);
1568 std::vector<unsigned int>
1569 ConsensusAlgorithmsPayload::answer_request(
1570 const unsigned int other_rank,
1574 std::vector<unsigned int> request_buffer;
1576 unsigned int owner_index_guess = 0;
1577 for (
const auto &interval : buffer_recv)
1578 for (auto i = interval.
first; i < interval.second; ++i)
1580 const unsigned int actual_owner =
1581 dict.actually_owning_ranks[i -
dict.local_range.first];
1582 request_buffer.push_back(actual_owner);
1585 append_index_origin(i -
dict.local_range.first,
1591 return request_buffer;
1597 ConsensusAlgorithmsPayload::process_answer(
1598 const unsigned int other_rank,
1599 const std::vector<unsigned int> &recv_buffer)
1601 const auto &recv_indices =
1604 for (
unsigned int j = 0; j < recv_indices.size(); ++j)
1610 std::map<unsigned int, IndexSet>
1611 ConsensusAlgorithmsPayload::get_requesters()
1614 ExcMessage(
"Must enable index range tracking in "
1615 "constructor of ConsensusAlgorithmProcess"));
1617 std::map<unsigned int, ::IndexSet> requested_indices;
1619#ifdef DEAL_II_WITH_MPI
1621 static CollectiveMutex mutex;
1622 CollectiveMutex::ScopedLock lock(mutex,
comm);
1631 std::vector<MPI_Request> send_requests;
1642 std::vector<std::vector<types::global_dof_index>> send_data(
1644 for (
unsigned int i = 0; i <
requesters.size(); ++i)
1653 IndexSet &my_index_set = requested_indices[j.first];
1655 for (
const auto &interval : j.
second)
1656 my_index_set.add_range(index_offset + interval.
first,
1657 index_offset + interval.
second);
1664 send_data[i].push_back(j.first);
1665 send_data[i].push_back(j.second.size());
1666 for (
const auto &interval : j.
second)
1668 send_data[i].push_back(interval.first);
1669 send_data[i].push_back(interval.second);
1672 send_requests.push_back(MPI_Request());
1674 MPI_Isend(send_data[i].
data(),
1675 send_data[i].
size(),
1678 dict.actually_owning_rank_list[i],
1681 &send_requests.back());
1687 for (
unsigned int c = 0; c <
dict.n_dict_procs_in_owned_indices; ++c)
1691 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1696 ierr = MPI_Get_count(
1698 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1705 std::pair<types::global_dof_index, types::global_dof_index>>
1706 buffer(number_amount / 2);
1710 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1720 dict.get_index_offset(status.MPI_SOURCE);
1721 unsigned int offset = 0;
1722 while (offset < buffer.size())
1728 for (
unsigned int i = offset + 1;
1729 i < offset + buffer[offset].second + 1;
1731 my_index_set.
add_range(index_offset + buffer[i].first,
1732 index_offset + buffer[i].second);
1737 IndexSet &index_set = requested_indices[buffer[offset].first];
1738 if (index_set.
size() == 0)
1742 offset += buffer[offset].second + 1;
1747 if (send_requests.size() > 0)
1749 const auto ierr = MPI_Waitall(send_requests.size(),
1750 send_requests.data(),
1751 MPI_STATUSES_IGNORE);
1757 for (
const auto &it : requested_indices)
1763 "The indices requested from the current "
1764 "MPI rank should be locally owned here!"));
1770 return requested_indices;
1776 ConsensusAlgorithmsPayload::append_index_origin(
1778 const unsigned int rank_of_request,
1779 const unsigned int rank_of_owner,
1780 unsigned int &owner_index_guess)
1787 dict.get_owning_rank_index(rank_of_owner, owner_index_guess);
1789 auto &request =
requesters[owner_index_guess];
1790 if (request.empty() || request.back().first != rank_of_request)
1791 request.emplace_back(
1794 std::pair<types::global_dof_index, types::global_dof_index>>());
1796 auto &intervals = request.back().second;
1797 if (intervals.empty() || intervals.back().second != index_within_dict)
1798 intervals.emplace_back(index_within_dict, index_within_dict + 1);
1800 ++intervals.back().second;