85template <
class Container = std::vector<std::
int32_t>>
88 static_assert(std::is_integral_v<typename Container::value_type>);
91 friend class Scatterer;
105 : _sizes_remote(map.src().size(), 0),
106 _displs_remote(map.src().size() + 1), _sizes_local(map.dest().size()),
107 _displs_local(map.dest().size() + 1)
113 const std::span<const int> src = map.
src();
114 const std::span<const int> dest = map.
dest();
117 assert(std::ranges::is_sorted(src));
118 assert(std::ranges::is_sorted(dest));
124 ierr = MPI_Dist_graph_create_adjacent(
125 map.
comm(), src.size(), src.data(), MPI_UNWEIGHTED, dest.size(),
126 dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
131 ierr = MPI_Dist_graph_create_adjacent(
132 map.
comm(), dest.size(), dest.data(), MPI_UNWEIGHTED, src.size(),
133 src.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm1);
138 std::span owners = map.
owners();
139 std::vector<std::int32_t> perm(owners.size());
140 std::iota(perm.begin(), perm.end(), 0);
145 std::span ghosts = map.
ghosts();
146 std::vector<int> owners_sorted(owners.size());
147 std::vector<std::int64_t> ghosts_sorted(owners.size());
148 std::ranges::transform(perm, owners_sorted.begin(),
149 [&owners](
auto idx) { return owners[idx]; });
150 std::ranges::transform(perm, ghosts_sorted.begin(),
151 [&ghosts](
auto idx) { return ghosts[idx]; });
159 assert(_sizes_remote.size() == src.size());
160 assert(_displs_remote.size() == src.size() + 1);
161 auto begin = owners_sorted.begin();
162 for (std::size_t i = 0; i < src.size(); i++)
164 auto upper = std::ranges::upper_bound(begin, owners_sorted.end(), src[i]);
165 std::size_t num_ind = std::ranges::distance(begin, upper);
166 _displs_remote[i + 1] = _displs_remote[i] + num_ind;
167 _sizes_remote[i] = num_ind;
178 assert(_sizes_local.size() == dest.size());
179 assert(_displs_local.size() == dest.size() + 1);
180 _sizes_remote.reserve(1);
181 _sizes_local.reserve(1);
183 = MPI_Neighbor_alltoall(_sizes_remote.data(), 1, MPI_INT,
184 _sizes_local.data(), 1, MPI_INT, _comm1.comm());
187 std::inclusive_scan(_sizes_local.begin(), _sizes_local.end(),
188 std::next(_displs_local.begin()));
190 assert(
static_cast<int>(ghosts_sorted.size()) == _displs_remote.back());
194 std::vector<std::int64_t> recv_buffer(_displs_local.back(), 0);
195 ierr = MPI_Neighbor_alltoallv(
196 ghosts_sorted.data(), _sizes_remote.data(), _displs_remote.data(),
197 MPI_INT64_T, recv_buffer.data(), _sizes_local.data(),
198 _displs_local.data(), MPI_INT64_T, _comm1.comm());
201 const std::array<std::int64_t, 2> range = map.
local_range();
204 std::ranges::for_each(recv_buffer, [range](
auto idx)
205 { assert(idx >= range[0] and idx < range[1]); });
213 std::vector<typename container_type::value_type> idx(recv_buffer.size());
214 std::ranges::transform(recv_buffer, idx.begin(),
215 [offset = range[0]](
auto i) ->
216 typename container_type::value_type
217 { return i - offset; });
218 _local_inds = std::move(idx);
242 : _comm0(s._comm0), _comm1(s._comm1),
243 _remote_inds(s._remote_inds.begin(), s._remote_inds.end()),
244 _sizes_remote(s._sizes_remote), _displs_remote(s._displs_remote),
245 _local_inds(s._local_inds.begin(), s._local_inds.end()),
246 _sizes_local(s._sizes_local), _displs_local(s._displs_local)
269 Scatterer& operator=(
const Scatterer& scatterer) =
delete;
320 template <
typename T>
322 MPI_Datatype type, MPI_Request& request)
const
324 if (!has_neighbours())
326 request = MPI_REQUEST_NULL;
330 int ierr = MPI_Ineighbor_alltoallv(
331 send_buffer, _sizes_local.data(), _displs_local.data(), type,
332 recv_buffer, _sizes_remote.data(), _displs_remote.data(), type,
333 _comm0.comm(), &request);
358 template <
typename T>
360 MPI_Request& request)
const
364 if (!has_neighbours())
366 request = MPI_REQUEST_NULL;
388 if (!has_neighbours())
391 wait(_comm0, request);
437 template <
typename T>
439 MPI_Datatype type, MPI_Request& request)
const
441 if (!has_neighbours())
443 request = MPI_REQUEST_NULL;
447 int ierr = MPI_Ineighbor_alltoallv(
448 send_buffer, _sizes_remote.data(), _displs_remote.data(), type,
449 recv_buffer, _sizes_local.data(), _displs_local.data(), type,
450 _comm1.comm(), &request);
475 template <
typename T>
477 MPI_Request& request)
const
481 if (!has_neighbours())
483 request = MPI_REQUEST_NULL;
505 if (!has_neighbours())
508 wait(_comm1, request);
590 bool has_neighbours() const noexcept
592 return _comm0.comm() != MPI_COMM_NULL;
598 int ierr = MPI_Wait(&request, MPI_STATUS_IGNORE);
614 dolfinx::MPI::Comm _comm1{MPI_COMM_NULL};
620 std::vector<int> _sizes_remote;
623 std::vector<int> _displs_remote;
631 std::vector<int> _sizes_local;
634 std::vector<int> _displs_local;
655template <
class Container>
656std::vector<std::int32_t>
658 std::span<const std::int32_t> indices,
int bs)
662 throw std::invalid_argument(
663 std::format(
"Block size must be positive, not {}.", bs));
666 const std::int32_t size_local = map.
size_local();
667 const std::int32_t num_blocks = size_local + map.
num_ghosts();
670 for (std::int32_t i : indices)
672 if (i < 0 or i / bs >= num_blocks)
673 throw std::out_of_range(
"Local index out of range.");
679 std::vector<std::int32_t> count(num_blocks, 1);
682 for (std::int32_t i : local)
685 std::vector<std::int32_t> send(local.size());
686 std::ranges::transform(local, send.begin(),
687 [&count](std::int32_t i) { return count[i]; });
688 std::vector<std::int32_t> recv(remote.size());
689 MPI_Request request = MPI_REQUEST_NULL;
692 for (std::size_t i = 0; i < remote.size(); ++i)
693 count[size_local + remote[i]] = recv[i];
695 std::vector<std::int32_t> n(indices.size());
696 std::ranges::transform(indices, n.begin(), [&count, bs](std::int32_t i)
697 { return count[i / bs]; });
A duplicate MPI communicator and manage lifetime of the communicator.
Definition MPI.h:47
MPI_Comm comm() const noexcept
Return the underlying MPI_Comm object.
Definition MPI.cpp:71
An MPI datatype for count contiguous values of type T, and manage its lifetime.
Definition MPI.h:346
MPI_Datatype type() const noexcept
The datatype to pass to MPI.
Definition MPI.h:395
Distribution of a global index range [0, N) across MPI ranks.
Definition IndexMap.h:191
std::int32_t num_ghosts() const noexcept
Return the number of ghost indices.
Definition IndexMap.cpp:1076
std::span< const int > dest() const noexcept
Return sorted unique ranks that ghost entries owned by the caller.
Definition IndexMap.cpp:1381
std::array< std::int64_t, 2 > local_range() const noexcept
Return the global range of owned indices.
Definition IndexMap.cpp:1071
std::span< const int > owners() const noexcept
Return ranks that own ghost entries.
Definition IndexMap.h:364
std::int32_t size_local() const noexcept
Return the number of owned indices.
Definition IndexMap.cpp:1081
std::span< const int > src() const noexcept
Return sorted unique ranks that own the caller's ghosts.
Definition IndexMap.cpp:1379
std::span< const std::int64_t > ghosts() const noexcept
Return global indices of ghosts in local ghost-index order.
Definition IndexMap.cpp:1088
MPI_Comm comm() const
Return the communicator that the map is defined on.
Definition IndexMap.cpp:1170
A Scatterer supports the scattering and gathering of distributed data that is associated with a commo...
Definition Scatterer.h:87
Scatterer(const IndexMap &map)
Create a scatterer for data with a layout described by an IndexMap.
Definition Scatterer.h:104
void scatter_rev_begin_dtype(const T *send_buffer, T *recv_buffer, MPI_Datatype type, MPI_Request &request) const
Start a non-blocking neighbourhood collective exchange of ghost data with the owning ranks.
Definition Scatterer.h:438
void scatter_fwd_begin(const T *send_buffer, T *recv_buffer, int bs, MPI_Request &request) const
Start a non-blocking neighbourhood collective exchange of owned data with the ranks that ghost it.
Definition Scatterer.h:359
Scatterer(Scatterer &&scatterer)=default
void scatter_rev_end(MPI_Request &request) const
Complete a non-blocking MPI neighbourhood collective send.
Definition Scatterer.h:503
const container_type & local_indices_block() const noexcept
Array of indices for packing/unpacking owned data to/from a send/receive buffer.
Definition Scatterer.h:548
void scatter_fwd_begin_dtype(const T *send_buffer, T *recv_buffer, MPI_Datatype type, MPI_Request &request) const
Start a non-blocking neighbourhood collective exchange of owned data with the ranks that ghost it.
Definition Scatterer.h:321
Scatterer & operator=(Scatterer &&scatterer)=default
void scatter_rev_begin(const T *send_buffer, T *recv_buffer, int bs, MPI_Request &request) const
Start a non-blocking neighbourhood collective exchange of ghost data with the owning ranks.
Definition Scatterer.h:476
Container container_type
Container type used to store local and remote indices.
Definition Scatterer.h:95
void scatter_fwd_end(MPI_Request &request) const
Complete a non-blocking MPI neighbourhood collective send.
Definition Scatterer.h:386
const container_type & remote_indices_block() const noexcept
Array of indices for packing/unpacking ghost data to/from a send/receive buffer.
Definition Scatterer.h:583
Scatterer(const Scatterer< U > &s)
Cast-copy constructor.
Definition Scatterer.h:241
Scatterer(const Scatterer &scatterer)=default
void check_error(MPI_Comm comm, int code) noexcept
Check MPI error code. If the error code is not equal to MPI_SUCCESS, then std::abort is called.
Definition MPI.cpp:89
int size(MPI_Comm comm)
Definition MPI.cpp:81
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
std::vector< std::int32_t > num_sharing_ranks(const IndexMap &map, std::span< const std::int32_t > indices, int bs)
Number of ranks that share each of the given local indices.
Definition IndexMap.cpp:933
constexpr void radix_sort(R &&range, P proj={})
Sort a range with radix sorting algorithm. The bucket size is determined by the number of bits to sor...
Definition sort.h:81