31template <
class Allocator = std::allocator<std::
int32_t>>
52 : _bs(
bs), _remote_inds(0, alloc), _local_inds(0, alloc),
53 _src(map.src().begin(), map.src().end()),
54 _dest(map.dest().begin(), map.dest().end())
60 assert(std::is_sorted(_src.begin(), _src.end()));
61 assert(std::is_sorted(_dest.begin(), _dest.end()));
67 MPI_Dist_graph_create_adjacent(
68 map.
comm(), _src.size(), _src.data(), MPI_UNWEIGHTED, _dest.size(),
69 _dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
73 MPI_Dist_graph_create_adjacent(
74 map.
comm(), _dest.size(), _dest.data(), MPI_UNWEIGHTED, _src.size(),
75 _src.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm1);
79 std::span owners = map.
owners();
80 std::vector<std::int32_t> perm(owners.size());
81 std::iota(perm.begin(), perm.end(), 0);
82 dolfinx::argsort_radix<std::int32_t>(owners, perm);
86 std::span ghosts = map.
ghosts();
87 std::vector<int> owners_sorted(owners.size());
88 std::vector<std::int64_t> ghosts_sorted(owners.size());
89 std::transform(perm.begin(), perm.end(), owners_sorted.begin(),
90 [&owners](
auto idx) { return owners[idx]; });
91 std::transform(perm.begin(), perm.end(), ghosts_sorted.begin(),
92 [&ghosts](
auto idx) { return ghosts[idx]; });
100 _sizes_remote.resize(_src.size(), 0);
101 _displs_remote.resize(_src.size() + 1, 0);
102 std::vector<std::int32_t>::iterator begin = owners_sorted.begin();
103 for (std::size_t i = 0; i < _src.size(); i++)
105 auto upper = std::upper_bound(begin, owners_sorted.end(), _src[i]);
106 int num_ind = std::distance(begin, upper);
107 _displs_remote[i + 1] = _displs_remote[i] + num_ind;
108 _sizes_remote[i] = num_ind;
119 _sizes_local.resize(_dest.size());
120 _displs_local.resize(_sizes_local.size() + 1);
121 _sizes_remote.reserve(1);
122 _sizes_local.reserve(1);
123 MPI_Neighbor_alltoall(_sizes_remote.data(), 1, MPI_INT32_T,
124 _sizes_local.data(), 1, MPI_INT32_T, _comm1.comm());
125 std::partial_sum(_sizes_local.begin(), _sizes_local.end(),
126 std::next(_displs_local.begin()));
128 assert((std::int32_t)ghosts_sorted.size() == _displs_remote.back());
129 assert((std::int32_t)ghosts_sorted.size() == _displs_remote.back());
133 std::vector<std::int64_t> recv_buffer(_displs_local.back(), 0);
134 MPI_Neighbor_alltoallv(ghosts_sorted.data(), _sizes_remote.data(),
135 _displs_remote.data(), MPI_INT64_T,
136 recv_buffer.data(), _sizes_local.data(),
137 _displs_local.data(), MPI_INT64_T, _comm1.comm());
139 const std::array<std::int64_t, 2> range = map.
local_range();
142 std::for_each(recv_buffer.begin(), recv_buffer.end(),
144 { assert(idx >= range[0] and idx < range[1]); });
149 auto rescale = [](
auto& x,
int bs)
151 std::transform(x.begin(), x.end(), x.begin(),
152 [
bs](
auto e) { return e *= bs; });
154 rescale(_sizes_local,
bs);
155 rescale(_displs_local,
bs);
156 rescale(_sizes_remote,
bs);
157 rescale(_displs_remote,
bs);
162 _local_inds = std::vector<std::int32_t, allocator_type>(
163 recv_buffer.size() * _bs, alloc);
164 std::int64_t offset = range[0] * _bs;
165 for (std::size_t i = 0; i < recv_buffer.size(); i++)
166 for (
int j = 0; j < _bs; j++)
167 _local_inds[i * _bs + j] = (recv_buffer[i] * _bs + j) - offset;
171 = std::vector<std::int32_t, allocator_type>(perm.size() * _bs, alloc);
172 for (std::size_t i = 0; i < perm.size(); i++)
173 for (
int j = 0; j < _bs; j++)
174 _remote_inds[i * _bs + j] = perm[i] * _bs + j;
197 template <
typename T>
199 std::span<T> recv_buffer,
200 std::span<MPI_Request> requests,
204 if (_sizes_local.empty() and _sizes_remote.empty())
211 assert(requests.size() == std::size_t(1));
212 MPI_Ineighbor_alltoallv(
213 send_buffer.data(), _sizes_local.data(), _displs_local.data(),
214 dolfinx::MPI::mpi_type<T>(), recv_buffer.data(), _sizes_remote.data(),
215 _displs_remote.data(), dolfinx::MPI::mpi_type<T>(), _comm0.comm(),
221 assert(requests.size() == _dest.size() + _src.size());
222 for (std::size_t i = 0; i < _src.size(); i++)
224 MPI_Irecv(recv_buffer.data() + _displs_remote[i], _sizes_remote[i],
225 dolfinx::MPI::mpi_type<T>(), _src[i], MPI_ANY_TAG,
226 _comm0.comm(), &requests[i]);
229 for (std::size_t i = 0; i < _dest.size(); i++)
231 MPI_Isend(send_buffer.data() + _displs_local[i], _sizes_local[i],
232 dolfinx::MPI::mpi_type<T>(), _dest[i], 0, _comm0.comm(),
233 &requests[i + _src.size()]);
238 throw std::runtime_error(
"Scatter::type not recognized");
253 if (_sizes_local.empty() and _sizes_remote.empty())
257 MPI_Waitall(requests.size(), requests.data(), MPI_STATUS_IGNORE);
280 template <
typename T,
typename F>
281 requires std::is_invocable_v<F, std::span<const T>,
282 std::span<const std::int32_t>, std::span<T>>
284 std::span<T> local_buffer, std::span<T> remote_buffer,
285 F pack_fn, std::span<MPI_Request> requests,
288 assert(local_buffer.size() == _local_inds.size());
289 assert(remote_buffer.size() == _remote_inds.size());
290 pack_fn(local_data, _local_inds, local_buffer);
314 template <
typename T,
typename F>
315 requires std::is_invocable_v<F, std::span<const T>,
316 std::span<const std::int32_t>, std::span<T>,
317 std::function<T(T, T)>>
319 std::span<T> remote_data, F unpack_fn,
320 std::span<MPI_Request> requests)
const
322 assert(remote_buffer.size() == _remote_inds.size());
323 assert(remote_data.size() == _remote_inds.size());
325 unpack_fn(remote_buffer, _remote_inds, remote_data,
326 [](T , T b) {
return b; });
340 template <
typename T>
342 std::span<T> remote_data)
const
344 std::vector<MPI_Request> requests(1, MPI_REQUEST_NULL);
347 auto pack_fn = [](
auto&& in,
auto&& idx,
auto&& out)
349 for (std::size_t i = 0; i < idx.size(); ++i)
353 std::span<T>(remote_buffer), pack_fn,
354 std::span<MPI_Request>(requests));
356 auto unpack_fn = [](
auto&& in,
auto&& idx,
auto&& out,
auto op)
358 for (std::size_t i = 0; i < idx.size(); ++i)
359 out[idx[i]] = op(out[idx[i]], in[i]);
362 scatter_fwd_end(std::span<const T>(remote_buffer), remote_data, unpack_fn,
363 std::span<MPI_Request>(requests));
392 template <
typename T>
394 std::span<T> recv_buffer,
395 std::span<MPI_Request> requests,
399 if (_sizes_local.empty() and _sizes_remote.empty())
408 assert(requests.size() == 1);
409 MPI_Ineighbor_alltoallv(send_buffer.data(), _sizes_remote.data(),
410 _displs_remote.data(), MPI::mpi_type<T>(),
411 recv_buffer.data(), _sizes_local.data(),
412 _displs_local.data(), MPI::mpi_type<T>(),
413 _comm1.comm(), &requests[0]);
418 assert(requests.size() == _dest.size() + _src.size());
420 for (std::size_t i = 0; i < _dest.size(); i++)
422 MPI_Irecv(recv_buffer.data() + _displs_local[i], _sizes_local[i],
423 dolfinx::MPI::mpi_type<T>(), _dest[i], MPI_ANY_TAG,
424 _comm0.comm(), &requests[i]);
429 for (std::size_t i = 0; i < _src.size(); i++)
431 MPI_Isend(send_buffer.data() + _displs_remote[i], _sizes_remote[i],
432 dolfinx::MPI::mpi_type<T>(), _src[i], 0, _comm0.comm(),
433 &requests[i + _dest.size()]);
438 throw std::runtime_error(
"Scatter::type not recognized");
453 if (_sizes_local.empty() and _sizes_remote.empty())
457 MPI_Waitall(request.size(), request.data(), MPI_STATUS_IGNORE);
484 template <
typename T,
typename F>
485 requires std::is_invocable_v<F, std::span<const T>,
486 std::span<const std::int32_t>, std::span<T>>
488 std::span<T> remote_buffer, std::span<T> local_buffer,
489 F pack_fn, std::span<MPI_Request> request,
492 assert(local_buffer.size() == _local_inds.size());
493 assert(remote_buffer.size() == _remote_inds.size());
494 pack_fn(remote_data, _remote_inds, remote_buffer);
518 template <
typename T,
typename F,
typename BinaryOp>
519 requires std::is_invocable_v<F, std::span<const T>,
520 std::span<const std::int32_t>, std::span<T>,
522 and std::is_invocable_r_v<T, BinaryOp, T, T>
524 F unpack_fn, BinaryOp op, std::span<MPI_Request> request)
526 assert(local_buffer.size() == _local_inds.size());
527 if (!_local_inds.empty())
529 assert(*std::max_element(_local_inds.begin(), _local_inds.end())
530 < std::int32_t(local_data.size()));
533 unpack_fn(local_buffer, _local_inds, local_data, op);
538 template <
typename T,
typename BinaryOp>
539 void scatter_rev(std::span<T> local_data, std::span<const T> remote_data,
544 auto pack_fn = [](
auto&& in,
auto&& idx,
auto&& out)
546 for (std::size_t i = 0; i < idx.size(); ++i)
549 auto unpack_fn = [](
auto&& in,
auto&& idx,
auto&& out,
auto op)
551 for (std::size_t i = 0; i < idx.size(); ++i)
552 out[idx[i]] = op(out[idx[i]], in[i]);
554 std::vector<MPI_Request> request(1, MPI_REQUEST_NULL);
556 std::span<T>(local_buffer), pack_fn,
557 std::span<MPI_Request>(request));
558 scatter_rev_end(std::span<const T>(local_buffer), local_data, unpack_fn, op,
559 std::span<MPI_Request>(request));
572 return _remote_inds.size();
593 int bs() const noexcept {
return _bs; }
600 std::vector<MPI_Request> requests;
604 requests = {MPI_REQUEST_NULL};
607 requests.resize(_dest.size() + _src.size(), MPI_REQUEST_NULL);
610 throw std::runtime_error(
"Scatter::type not recognized");
634 std::vector<std::int32_t, allocator_type> _remote_inds;
637 std::vector<int> _sizes_remote;
640 std::vector<int> _displs_remote;
645 std::vector<std::int32_t, allocator_type> _local_inds;
648 std::vector<int> _sizes_local;
651 std::vector<int> _displs_local;
655 std::vector<int> _src;
659 std::vector<int> _dest;
A duplicate MPI communicator and manage lifetime of the communicator.
Definition MPI.h:43
This class represents the distribution index arrays across processes. An index array is a contiguous ...
Definition IndexMap.h:94
std::span< const int > owners() const
The ranks that own each ghost index.
Definition IndexMap.h:205
std::array< std::int64_t, 2 > local_range() const noexcept
Range of indices (global) owned by this process.
Definition IndexMap.cpp:861
std::span< const std::int64_t > ghosts() const noexcept
Local-to-global map for ghosts (local indexing beyond end of local range)
Definition IndexMap.cpp:875
MPI_Comm comm() const
Return the MPI communicator that the map is defined on.
Definition IndexMap.cpp:940
A Scatterer supports the MPI scattering and gathering of data that is associated with a common::Index...
Definition Scatterer.h:33
std::vector< MPI_Request > create_request_vector(Scatterer::type type=type::neighbor)
Create a vector of MPI_Requests for a given Scatterer::type.
Definition Scatterer.h:597
Allocator allocator_type
The allocator type.
Definition Scatterer.h:36
void scatter_fwd_end(std::span< MPI_Request > requests) const
Complete a non-blocking send from the local owner to process ranks that have the index as a ghost.
Definition Scatterer.h:250
void scatter_fwd(std::span< const T > local_data, std::span< T > remote_data) const
Scatter data associated with owned indices to ghosting ranks.
Definition Scatterer.h:341
Scatterer(const IndexMap &map, int bs, const Allocator &alloc=Allocator())
Create a scatterer.
Definition Scatterer.h:51
std::int32_t remote_buffer_size() const noexcept
Buffer size for remote data (ghosts) used in forward and reverse communication.
Definition Scatterer.h:570
std::int32_t local_buffer_size() const noexcept
Size of buffer for local data (owned and shared) used in forward and reverse communication.
Definition Scatterer.h:565
void scatter_fwd_end(std::span< const T > remote_buffer, std::span< T > remote_data, F unpack_fn, std::span< MPI_Request > requests) const
Complete a non-blocking send from the local owner to process ranks that have the index as a ghost,...
Definition Scatterer.h:318
and std::is_invocable_r_v< T, BinaryOp, T, T > void scatter_rev_end(std::span< const T > local_buffer, std::span< T > local_data, F unpack_fn, BinaryOp op, std::span< MPI_Request > request)
End the reverse scatter communication, and unpack the received local buffer into local data.
Definition Scatterer.h:523
void scatter_rev_begin(std::span< const T > remote_data, std::span< T > remote_buffer, std::span< T > local_buffer, F pack_fn, std::span< MPI_Request > request, Scatterer::type type=type::neighbor) const
Scatter data associated with ghost indices to owning ranks.
Definition Scatterer.h:487
type
Types of MPI communication pattern used by the Scatterer.
Definition Scatterer.h:40
void scatter_rev_end(std::span< MPI_Request > request) const
End the reverse scatter communication.
Definition Scatterer.h:450
void scatter_fwd_begin(std::span< const T > send_buffer, std::span< T > recv_buffer, std::span< MPI_Request > requests, Scatterer::type type=type::neighbor) const
Start a non-blocking send of owned data to ranks that ghost the data.
Definition Scatterer.h:198
const std::vector< std::int32_t > & local_indices() const noexcept
Return a vector of local indices (owned) used to pack/unpack local data. These indices are grouped by...
Definition Scatterer.h:578
const std::vector< std::int32_t > & remote_indices() const noexcept
Return a vector of remote indices (ghosts) used to pack/unpack ghost data. These indices are grouped ...
Definition Scatterer.h:585
void scatter_rev(std::span< T > local_data, std::span< const T > remote_data, BinaryOp op)
Scatter data associated with ghost indices to ranks that own the indices.
Definition Scatterer.h:539
int bs() const noexcept
The number values (block size) to send per index in the common::IndexMap use to create the scatterer.
Definition Scatterer.h:593
void scatter_fwd_begin(std::span< const T > local_data, std::span< T > local_buffer, std::span< T > remote_buffer, F pack_fn, std::span< MPI_Request > requests, Scatterer::type type=type::neighbor) const
Scatter data associated with owned indices to ghosting ranks.
Definition Scatterer.h:283
void scatter_rev_begin(std::span< const T > send_buffer, std::span< T > recv_buffer, std::span< MPI_Request > requests, Scatterer::type type=type::neighbor) const
Start a non-blocking send of ghost data to ranks that own the data.
Definition Scatterer.h:393
int size(MPI_Comm comm)
Return size of the group (number of processes) associated with the communicator.
Definition MPI.cpp:72
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
Top-level namespace.
Definition defines.h:12