701 namespace ComputeIndexOwner
703 class FlexibleIndexStorage
706 using index_type =
unsigned int;
710 FlexibleIndexStorage(
const bool use_vector =
true);
713 reinit(
const bool use_vector,
714 const bool index_range_contiguous,
715 const std::size_t size);
718 fill(
const std::size_t start,
719 const std::size_t
end,
720 const index_type &value);
723 operator[](
const std::size_t index);
726 operator[](
const std::size_t index)
const;
728 [[maybe_unused]]
bool
729 entry_has_been_set(
const std::size_t index)
const;
813 std::pair<types::global_dof_index, types::global_dof_index>
854 get_index_offset(
const unsigned int rank);
862 get_owning_rank_index(
const unsigned int rank_in_owned_indices,
863 const unsigned int guess = 0);
882 class ConsensusAlgorithmsPayload
885 using RequestType = std::vector<
886 std::pair<types::global_dof_index, types::global_dof_index>>;
887 using AnswerType = std::vector<unsigned int>;
892 ConsensusAlgorithmsPayload(
const IndexSet &owned_indices,
895 std::vector<unsigned int> &owning_ranks,
896 const bool track_index_requesters =
false);
954 std::vector<std::vector<
955 std::pair<
unsigned int,
965 std::map<
unsigned int,
966 std::pair<std::vector<types::global_dof_index>,
967 std::vector<unsigned int>>>
973 std::vector<unsigned int>
980 std::pair<types::global_dof_index, types::global_dof_index>>
981 create_request(
const unsigned int other_rank);
986 std::vector<unsigned int>
988 const unsigned int other_rank,
997 process_answer(
const unsigned int other_rank,
998 const std::vector<unsigned int> &recv_buffer);
1015 std::map<unsigned int, IndexSet>
1033 append_index_origin(
1035 const unsigned int rank_of_request,
1036 const unsigned int rank_of_owner,
1037 unsigned int &owner_index_guess);
1052 Dictionary::get_index_offset(
const unsigned int rank)
1064 Dictionary::get_owning_rank_index(
1065 const unsigned int rank_in_owned_indices,
1066 const unsigned int guess)
1075 rank_in_owned_indices);
1083 const FlexibleIndexStorage::index_type
1084 FlexibleIndexStorage::invalid_index_value;
1088 FlexibleIndexStorage::FlexibleIndexStorage(
const bool use_vector)
1096 FlexibleIndexStorage::reinit(
const bool use_vector,
1097 const bool index_range_contiguous,
1098 const std::size_t
size)
1115 FlexibleIndexStorage::fill(
1116 const std::size_t start,
1117 const std::size_t
end,
1118 const FlexibleIndexStorage::index_type &value)
1125 if (
data.empty() &&
end > start)
1137 std::fill(
data.begin() + start,
1149 std::fill(
data.begin() + start,
data.begin() +
end, value);
1154 for (
auto i = start; i <
end; ++i)
1161 FlexibleIndexStorage::index_type &
1162 FlexibleIndexStorage::operator[](
const std::size_t index)
1180 [[maybe_unused]]
bool
1181 FlexibleIndexStorage::entry_has_been_set(
const std::size_t index)
const
1208 std::map<
unsigned int,
1213 const auto owned_indices_size_actual =
1218 owned_indices_size_actual ==
1231 std::pair<types::global_dof_index, types::global_dof_index>
1232 index_range(*interval->begin(), interval->last() + 1);
1236 while (index_range.first != index_range.second)
1238 Assert(index_range.first < index_range.second,
1241 const unsigned int owner =
1242 dof_to_dict_rank(index_range.first);
1247 std::min(get_index_offset(owner + 1), index_range.second);
1269 dic_local_received += next_index - index_range.first;
1274 buffers[owner].emplace_back(index_range.first, next_index);
1276 index_range.first = next_index;
1280#ifdef DEAL_II_WITH_MPI
1282 std::vector<MPI_Request> request;
1296 static CollectiveMutex mutex;
1297 CollectiveMutex::ScopedLock lock(mutex,
comm);
1304 for (
const auto &rank_pair : buffers)
1306 request.push_back(MPI_Request());
1308 MPI_Isend(rank_pair.second.data(),
1309 rank_pair.second.size() * 2,
1320 while (this->locally_owned_size != dic_local_received)
1324 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1329 ierr = MPI_Get_count(&status,
1335 const auto other_rank = status.MPI_SOURCE;
1341 std::pair<types::global_dof_index, types::global_dof_index>>
1342 buffer(number_amount / 2);
1343 ierr = MPI_Recv(buffer.data(),
1353 for (
auto interval : buffer)
1359 i < interval.second;
1377 dic_local_received += interval.second - interval.first;
1389 using RequestType = std::vector<
1390 std::pair<types::global_dof_index, types::global_dof_index>>;
1392 std::vector<unsigned int> targets;
1393 targets.reserve(buffers.size());
1394 for (
const auto &rank_pair : buffers)
1395 targets.emplace_back(rank_pair.
first);
1397 ConsensusAlgorithms::selector<RequestType>(
1401 [&buffers](
const unsigned int target_rank) -> RequestType {
1402 return buffers.at(target_rank);
1406 [&](
const unsigned int source_rank,
1407 const RequestType &request) ->
void {
1409 for (
auto interval : request)
1415 i < interval.second;
1421 "Multiple processes seem to own the same global index. "
1422 "A possible reason is that the sets of locally owned "
1423 "indices are not distinct."));
1424 Assert(interval.first < interval.second,
1430 "The specified interval is not handled by the current process."));
1453 if (request.size() > 0)
1455 const int ierr = MPI_Waitall(request.size(),
1457 MPI_STATUSES_IGNORE);
1464 (void)dic_local_received;
1495 ConsensusAlgorithmsPayload::ConsensusAlgorithmsPayload(
1514 std::vector<unsigned int>
1515 ConsensusAlgorithmsPayload::compute_targets()
1517 std::vector<unsigned int> targets;
1520 unsigned int index = 0;
1521 unsigned int owner_index_guess = 0;
1524 unsigned int other_rank =
dict.dof_to_dict_rank(i);
1528 dict.actually_owning_ranks[i -
dict.local_range.first];
1530 append_index_origin(i -
dict.local_range.first,
1537 if (targets.empty() || targets.back() != other_rank)
1538 targets.push_back(other_rank);
1540 indices.first.push_back(i);
1541 indices.second.push_back(index);
1554 std::vector<std::pair<types::global_dof_index, types::global_dof_index>>
1555 ConsensusAlgorithmsPayload::create_request(
1556 const unsigned int other_rank)
1559 std::pair<types::global_dof_index, types::global_dof_index>>
1565 is.add_indices(indices_i.begin(), indices_i.end());
1568 for (
auto interval = is.begin_intervals();
1569 interval != is.end_intervals();
1571 send_buffer.emplace_back(*interval->begin(), interval->last() + 1);
1578 std::vector<unsigned int>
1579 ConsensusAlgorithmsPayload::answer_request(
1580 const unsigned int other_rank,
1584 std::vector<unsigned int> request_buffer;
1586 unsigned int owner_index_guess = 0;
1587 for (
const auto &interval : buffer_recv)
1588 for (auto i = interval.
first; i < interval.second; ++i)
1590 const unsigned int actual_owner =
1591 dict.actually_owning_ranks[i -
dict.local_range.first];
1592 request_buffer.push_back(actual_owner);
1595 append_index_origin(i -
dict.local_range.first,
1601 return request_buffer;
1607 ConsensusAlgorithmsPayload::process_answer(
1608 const unsigned int other_rank,
1609 const std::vector<unsigned int> &recv_buffer)
1611 const auto &recv_indices =
1614 for (
unsigned int j = 0; j < recv_indices.size(); ++j)
1620 std::map<unsigned int, IndexSet>
1621 ConsensusAlgorithmsPayload::get_requesters()
1624 ExcMessage(
"Must enable index range tracking in "
1625 "constructor of ConsensusAlgorithmProcess"));
1627 std::map<unsigned int, ::IndexSet> requested_indices;
1629#ifdef DEAL_II_WITH_MPI
1631 static CollectiveMutex mutex;
1632 CollectiveMutex::ScopedLock lock(mutex,
comm);
1641 std::vector<MPI_Request> send_requests;
1652 std::vector<std::vector<types::global_dof_index>> send_data(
1654 for (
unsigned int i = 0; i <
requesters.size(); ++i)
1663 IndexSet &my_index_set = requested_indices[j.first];
1665 for (
const auto &interval : j.
second)
1666 my_index_set.add_range(index_offset + interval.
first,
1667 index_offset + interval.
second);
1674 send_data[i].push_back(j.first);
1675 send_data[i].push_back(j.second.size());
1676 for (
const auto &interval : j.
second)
1678 send_data[i].push_back(interval.first);
1679 send_data[i].push_back(interval.second);
1682 send_requests.push_back(MPI_Request());
1684 MPI_Isend(send_data[i].
data(),
1685 send_data[i].
size(),
1688 dict.actually_owning_rank_list[i],
1691 &send_requests.back());
1697 for (
unsigned int c = 0; c <
dict.n_dict_procs_in_owned_indices; ++c)
1701 int ierr = MPI_Probe(MPI_ANY_SOURCE, mpi_tag,
comm, &status);
1706 ierr = MPI_Get_count(
1708 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1715 std::pair<types::global_dof_index, types::global_dof_index>>
1716 buffer(number_amount / 2);
1720 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
1730 dict.get_index_offset(status.MPI_SOURCE);
1731 unsigned int offset = 0;
1732 while (offset < buffer.size())
1738 for (
unsigned int i = offset + 1;
1739 i < offset + buffer[offset].second + 1;
1741 my_index_set.
add_range(index_offset + buffer[i].first,
1742 index_offset + buffer[i].second);
1747 IndexSet &index_set = requested_indices[buffer[offset].first];
1748 if (index_set.
size() == 0)
1752 offset += buffer[offset].second + 1;
1757 if (send_requests.size() > 0)
1759 const auto ierr = MPI_Waitall(send_requests.size(),
1760 send_requests.data(),
1761 MPI_STATUSES_IGNORE);
1768 for (
const auto &it : requested_indices)
1774 "The indices requested from the current "
1775 "MPI rank should be locally owned here!"));
1781 return requested_indices;
1787 ConsensusAlgorithmsPayload::append_index_origin(
1789 const unsigned int rank_of_request,
1790 const unsigned int rank_of_owner,
1791 unsigned int &owner_index_guess)
1798 dict.get_owning_rank_index(rank_of_owner, owner_index_guess);
1800 auto &request =
requesters[owner_index_guess];
1801 if (request.empty() || request.back().first != rank_of_request)
1802 request.emplace_back(
1805 std::pair<types::global_dof_index, types::global_dof_index>>());
1807 auto &intervals = request.back().second;
1808 if (intervals.empty() || intervals.back().second != index_within_dict)
1809 intervals.emplace_back(index_within_dict, index_within_dict + 1);
1811 ++intervals.back().second;