19 std::unordered_map<int, T> recv;
20 std::unordered_map<int, T> send;
29 T owned_variable_list;
30 T local_variable_list;
45 std::vector<T> inclusive_offsets(values_per_rank.size() + 1);
47 std::transform(values_per_rank.begin(), values_per_rank.end(), inclusive_offsets.begin() + 1,
48 [&](T& value) {
return offset += value; });
49 return inclusive_offsets;
63 std::tuple<T, std::vector<T>>
gatherVariablesPerRank(std::size_t local_vector_size,
bool gatherAll =
true,
int root = 0,
64 MPI_Comm comm = MPI_COMM_WORLD)
66 std::vector<T> local_size{
static_cast<T
>(local_vector_size)};
69 std::vector<T> size_on_rank(nranks);
70 std::vector<int> ones(nranks, 1);
71 std::vector<int> offsets(nranks);
72 std::iota(offsets.begin(), offsets.end(), 0);
76 mpi::Gatherv(local_size, size_on_rank, ones, offsets, root, comm);
80 for (
auto lsize : size_on_rank) {
83 return std::make_tuple(global_size, size_on_rank);
99 V
concatGlobalVector(
typename V::size_type global_size, std::vector<int>& variables_per_rank, std::vector<int>& offsets,
100 V& local_vector,
bool gatherAll =
true,
int root = 0, MPI_Comm comm = MPI_COMM_WORLD)
102 V global_vector(global_size);
105 mpi::Allgatherv(local_vector, global_vector, variables_per_rank, offsets, comm);
107 mpi::Gatherv(local_vector, global_vector, variables_per_rank, offsets, root, comm);
109 return global_vector;
113 template <
typename V>
114 V
concatGlobalVector(
typename V::size_type global_size, std::vector<int>& variables_per_rank, V& local_vector,
115 bool gatherAll =
true,
int root = 0, MPI_Comm comm = MPI_COMM_WORLD)
117 V global_vector(global_size);
121 return concatGlobalVector(global_size, variables_per_rank, offsets, local_vector, gatherAll, root, comm);
135 template <
typename T,
typename M,
typename I>
137 MPI_Comm comm = MPI_COMM_WORLD)
141 typename I::value_type current_rank = 0;
144 std::unordered_map<int, T>& recv = comm_info.recv;
145 std::unordered_map<int, T>& send = comm_info.send;
148 if (local_ids.size() > 0) {
149 for (
const auto& global_local_id : all_global_local_ids) {
151 auto global_offset = &global_local_id - &all_global_local_ids.front();
153 const auto global_offset_index =
static_cast<typename I::value_type
>(global_offset);
154 if (global_offset_index == offsets[current_rank + 1]) {
156 while (global_offset_index == offsets[current_rank + 1]) {
161 typename M::iterator found;
163 if (current_rank != my_rank && ((found = local_ids.find(global_local_id)) != local_ids.end())) {
166 if (current_rank < my_rank) {
168 send[current_rank].insert(send[current_rank].end(), (found->second).begin(), (found->second).end());
171 local_ids.erase(found);
172 }
else if (current_rank > my_rank) {
175 recv[current_rank].push_back(found->second[0]);
183 for (
auto & [rank, values] : recv) {
184 std::sort(values.begin(), values.end());
198 template <
typename V,
typename T>
201 std::unordered_map<int, T>& recv = info.recv;
202 std::unordered_map<int, T>& send = info.send;
205 std::vector<MPI_Request> requests;
206 std::unordered_map<int, V> recv_data;
207 for (
auto [recv_rank, recv_rank_vars] : recv) {
209 recv_data[recv_rank] = V(recv_rank_vars.size());
210 requests.push_back(MPI_Request());
212 mpi::Irecv(recv_data[recv_rank], recv_rank, &requests.back());
216 std::unordered_map<int, V> send_data;
217 for (
auto [send_to_rank, send_rank_vars] : send) {
218 send_data[send_to_rank] = V();
219 for (
auto s : send_rank_vars) {
220 send_data[send_to_rank].push_back(local_data[s]);
222 requests.push_back(MPI_Request());
224 mpi::Isend(send_data[send_to_rank], send_to_rank, &requests.back());
227 std::vector<MPI_Status> stats(requests.size());
229 if (error != MPI_SUCCESS) std::cout <<
"sendToOwner issue : " << error << std::endl;
243 template <
typename V,
typename T>
246 std::unordered_map<int, T>& recv = info.recv;
247 std::unordered_map<int, T>& send = info.send;
250 std::vector<MPI_Request> requests;
252 std::unordered_map<int, V> send_data;
253 for (
auto [send_to_rank, send_rank_vars] : send) {
255 send_data[send_to_rank] = V(send_rank_vars.size());
256 requests.push_back(MPI_Request());
258 mpi::Irecv(send_data[send_to_rank], send_to_rank, &requests.back());
262 std::unordered_map<int, V> recv_data;
263 for (
auto [recv_rank, recv_rank_vars] : recv) {
265 recv_data[recv_rank] = V();
266 for (
auto r : recv_rank_vars) {
267 recv_data[recv_rank].push_back(local_data[r]);
270 requests.push_back(MPI_Request());
272 mpi::Isend(recv_data[recv_rank], recv_rank, &requests.back());
275 std::vector<MPI_Status> stats(requests.size());
277 if (error != MPI_SUCCESS) std::cout <<
"returnToSender issue : " << error << std::endl;
302 template <
typename T,
typename M>
305 assert(results.size() >= vector.size());
307 assert(map.size() == 0 || (map.size() > 0 &&
static_cast<typename T::size_type
>(
308 *std::max_element(map.begin(), map.end())) <= results.size()));
309 for (
typename T::size_type i = 0; i < vector.size(); i++) {
310 results[map[i]] = vector[i];
336 template <
typename T,
typename M>
338 std::optional<typename T::size_type> arg_size = std::nullopt)
341 typename T::size_type results_size = arg_size ? *arg_size : vector.size();
342 assert(results_size >= vector.size());
343 assert(static_cast<typename T::size_type>(*std::max_element(map.begin(), map.end())) <= results_size);
344 T results(results_size, pad_value);
367 template <
typename T,
typename M>
370 assert((map.size() > 0 &&
371 static_cast<typename T::size_type
>(*std::max_element(map.begin(), map.end())) <= vector.size()) ||
373 assert(map.size() <= vector.size());
374 T result(map.size());
375 for (
typename T::size_type i = 0; i < result.size(); i++) {
376 result[i] = vector[map[i]];
389 template <
typename T,
typename M,
typename I>
392 assert(map.size() <= vector.size());
393 T result(map.size());
394 for (
typename T::size_type i = 0; i < result.size(); i++) {
395 result[i] = vector[global_ids_of_local_vector[map[i]][0]];
400 template <
typename T>
401 using inverseMapType = std::unordered_map<typename T::value_type, T>;
416 template <
typename T>
419 inverseMapType<T> map;
420 typename T::size_type counter = 0;
421 for (
auto v : vector_map) {
422 if (map.find(v) != map.end()) {
423 map[v].push_back(counter);
431 for (
auto& [k, v] : map) {
432 std::sort(v.begin(), v.end());
445 template <
typename K,
typename V>
449 for (
auto [k, v] : map) {
464 template <
typename T,
typename V>
465 std::unordered_map<typename T::value_type, V>
remapRecvData(std::unordered_map<int, T>& recv,
466 std::unordered_map<int, V>& recv_data)
470 std::unordered_map<typename T::value_type, V> remap;
471 for (
auto [recv_rank, local_inds] : recv) {
472 for (
auto& local_ind : local_inds) {
473 auto index = &local_ind - &local_inds.front();
474 auto value = recv_data[recv_rank][
static_cast<size_t>(index)];
477 remap[local_ind].push_back(value);
496 template <
typename T,
typename V>
498 std::unordered_map<typename T::value_type, T>& global_to_local_map, V& local_variables)
503 for (
auto [_, local_ids] : global_to_local_map) {
504 for (
auto local_id : local_ids) {
505 remap[local_ids[0]].push_back(local_variables.at(local_id));
518 template <
typename M>
520 M& remapped_data, std::function<
typename M::mapped_type::value_type(
const typename M::mapped_type&)> reduce_op)
522 typename M::mapped_type reduced_data(remapped_data.size());
523 for (
auto [local_ind, data_to_reduce] : remapped_data) {
524 reduced_data[local_ind] = reduce_op(data_to_reduce);
530 namespace reductions {
534 template <
typename V>
535 static typename V::value_type sumOfCollection(
const V& collection)
537 typename V::value_type sum = 0;
538 for (
auto val : collection) {
547 template <
typename V>
548 static typename V::value_type firstOfCollection(
const V& collection)
550 return collection[0];
560 template <
typename T>
561 auto filterOut(
const T& global_local_ids, std::unordered_map<
int, std::vector<typename T::size_type>>& filter)
563 std::vector<typename T::size_type> remove_ids;
564 for (
auto [_, local_ids] : filter) {
565 remove_ids.insert(std::end(remove_ids), std::begin(local_ids), std::end(local_ids));
568 std::sort(remove_ids.begin(), remove_ids.end());
571 std::vector<typename T::size_type> local_id_range(global_local_ids.size());
572 std::vector<typename T::size_type> filtered(local_id_range.size());
573 std::iota(local_id_range.begin(), local_id_range.end(), 0);
574 if (remove_ids.size() > 0) {
575 auto it = std::set_difference(local_id_range.begin(), local_id_range.end(), remove_ids.begin(), remove_ids.end(),
577 filtered.resize(it - filtered.begin());
579 filtered = local_id_range;
583 T mapped(filtered.size());
584 std::transform(filtered.begin(), filtered.end(), mapped.begin(), [&](
auto& v) {
return global_local_ids[v]; });
int getRank(MPI_Comm comm=MPI_COMM_WORLD)
Get rank.
int Waitall(std::vector< MPI_Request > &requests, std::vector< MPI_Status > &status)
A wrapper to MPI_Waitall to wait for all the requests to be fulfilled.
auto inverseMap(T &vector_map)
Inverts a vector that providse a map into an unordered_map.
auto filterOut(const T &global_local_ids, std::unordered_map< int, std::vector< typename T::size_type >> &filter)
remove values in filter that correspond to global_local_ids
auto returnToSender(RankCommunication< T > &info, const V &local_data, MPI_Comm comm=MPI_COMM_WORLD)
transfer back data in reverse from sendToOwners
V concatGlobalVector(typename V::size_type global_size, std::vector< int > &variables_per_rank, std::vector< int > &offsets, V &local_vector, bool gatherAll=true, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Assemble a vector by concatination of local_vector across all ranks on a communicator.
T permuteAccessStore(T &vector, M &map)
Retrieves from T using a permuted mapping M and stores in order, result[i] = T[M[i]].
int Irecv(T &buf, int send_rank, MPI_Request *request, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Recieve a buffer from a specified rank and create a handle for the MPI_Request.
auto remapRecvDataIncludeLocal(std::unordered_map< int, T > &recv, std::unordered_map< int, V > &recv_data, std::unordered_map< typename T::value_type, T > &global_to_local_map, V &local_variables)
rearrange data so that map[rank]->local_ids and map[rank] -> V becomes map[local_ids]->values ...
void accessPermuteStore(T &vector, M &map, T &results)
Retrieves from T and stores in permuted mapping M, result[M[i]] = T[i].
T permuteMapAccessStore(T &vector, M &map, I &global_ids_of_local_vector)
Retrieves from T using a permuted mapping M and index mapping I stores in order, result[i] = T[I[M[i]...
std::unordered_map< typename T::value_type, V > remapRecvData(std::unordered_map< int, T > &recv, std::unordered_map< int, V > &recv_data)
rearrange data so that map[rank]->local_ids and map[rank] -> V becomes map[local_ids]->values ...
Complete Op communication pattern information.
std::vector< T > buildInclusiveOffsets(std::vector< T > &values_per_rank)
Takes in sizes per index and and performs a rank-local inclusive offset.
int Allgatherv(T &buf, T &values_on_rank, std::vector< int > &size_on_rank, std::vector< int > &offsets_on_rank, MPI_Comm comm=MPI_COMM_WORLD)
gathers a local collections from all ranks on all ranks on a communicator
int Gatherv(T &buf, T &values_on_rank, std::vector< int > &size_on_rank, std::vector< int > &offsets_on_rank, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
gathers a local collections from all ranks only on the root rank
std::unordered_map< int, V > sendToOwners(RankCommunication< T > &info, V &local_data, MPI_Comm comm=MPI_COMM_WORLD)
transfer data to owners
M::mapped_type reduceRecvData(M &remapped_data, std::function< typename M::mapped_type::value_type(const typename M::mapped_type &)> reduce_op)
apply reduction operation to recieved data
int getNRanks(MPI_Comm comm=MPI_COMM_WORLD)
Get number of ranks.
int Isend(T &buf, int recv_rank, MPI_Request *request, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Send a buffer to a specified rank and create a handle for the MPI_Request.
Holds communication information to and from rank.
auto mapToVector(std::unordered_map< K, V > &map)
Converts an inverseMap back to the vector representation.
std::tuple< T, std::vector< T > > gatherVariablesPerRank(std::size_t local_vector_size, bool gatherAll=true, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Get number of variables on each rank in parallel.
RankCommunication< T > generateSendRecievePerRank(M local_ids, T &all_global_local_ids, I &offsets, MPI_Comm comm=MPI_COMM_WORLD)
given a map of local_ids and global_ids determine send and recv communications