17#ifndef PECLET_CORE_HALO_GRID_HALO_TOPOLOGY_HPP
18#define PECLET_CORE_HALO_GRID_HALO_TOPOLOGY_HPP
42 std::memcpy(&
v,
src,
sizeof(
T));
58 indexer_.init(
dec.origins()[rank],
dec.sizes()[rank], ghostWidth);
67 if (indexer_.isInner(
lmd))
71 for (
int i = 0;
i < Dim; ++
i) {
72 g[
i] =
lmd[
i] + indexer_.originInclGhost()[
i];
86 int owner =
dec.ownerOf(
gw);
91 selfSrc_.push_back(indexer_.globalToLocal(
gw));
99 recvRanks_.push_back(
r);
100 recvIdx_.push_back(std::move(idx));
107 auto packNext = [&](std::vector<char>&
out) ->
int {
108 if (k >= recvRanks_.size())
110 int dest = recvRanks_[k];
111 const auto& g = recvGlob_[k];
113 out.resize(g.size() *
sizeof(
Index));
114 std::memcpy(
out.data(), g.data(),
out.size());
118 std::size_t n =
msg.size() /
sizeof(
Index);
120 std::vector<Index>
sidx(n);
121 for (std::size_t
i = 0;
i < n; ++
i) {
122 sidx[
i] = indexer_.globalToLocal(
dec.multiGlobal(g[
i]));
124 sendRanks_.push_back(
src);
125 sendIdx_.push_back(std::move(
sidx));
130 persistentReady_ =
false;
137 template <
typename Field>
139 applySelfCopy(field);
140 const std::size_t
es = field.bytesPerElem();
144 recvBufs_.resize(recvRanks_.size());
145 for (std::size_t k = 0; k < recvRanks_.size(); ++k) {
146 recvBufs_[k].resize(recvIdx_[k].size() *
es);
147 MPI_Irecv(recvBufs_[k].data(),
static_cast<int>(recvBufs_[k].size()),
MPI_BYTE, recvRanks_[k],
148 tag, comm_, &recvReqs_[k]);
152 sendBufs_.resize(sendRanks_.size());
153 for (std::size_t k = 0; k < sendRanks_.size(); ++k) {
154 auto&
buf = sendBufs_[k];
155 buf.resize(sendIdx_[k].size() *
es);
156 for (std::size_t
i = 0;
i < sendIdx_[k].size(); ++
i) {
157 field.pack(sendIdx_[k][
i],
buf.data() +
i *
es);
166 template <
typename Field>
168 const std::size_t
es = field.bytesPerElem();
170 for (std::size_t
done = 0;
done < recvReqs_.size(); ++
done) {
175 for (std::size_t
i = 0;
i < recvIdx_[k].size(); ++
i) {
176 field.unpack(recvIdx_[k][
i], recvBufs_[k].data() +
i *
es);
179 if (!sendReqs_.empty()) {
185 template <
typename Field>
196 template <
typename Field>
198 applySelfCopy(field);
199 const std::size_t
es = field.bytesPerElem();
203 for (std::size_t k = 0; k < sendRanks_.size(); ++k) {
204 char*
dst = graphSendBuf_.data() + graphSendDispl_[k];
205 for (std::size_t
i = 0;
i < sendIdx_[k].size(); ++
i) {
206 field.pack(sendIdx_[k][
i],
dst +
i *
es);
210 MPI_BYTE, graphRecvBuf_.data(), graphRecvCnt_.data(),
211 graphRecvDispl_.data(),
MPI_BYTE, graphComm_);
213 for (std::size_t k = 0; k < recvRanks_.size(); ++k) {
214 const char*
src = graphRecvBuf_.data() + graphRecvDispl_[k];
215 for (std::size_t
i = 0;
i < recvIdx_[k].size(); ++
i) {
216 field.unpack(recvIdx_[k][
i],
src +
i *
es);
227 template <
typename Field>
229 const std::size_t
es = field.bytesPerElem();
231 std::vector<char> tmp(
es);
232 for (std::size_t
i = 0;
i < selfSrc_.size(); ++
i) {
233 field.pack(selfDst_[
i], tmp.data());
234 field.addFrom(selfSrc_[
i], tmp.data());
237 std::vector<std::vector<char>>
rbuf(sendRanks_.size());
239 for (std::size_t k = 0; k < sendRanks_.size(); ++k) {
240 rbuf[k].resize(sendIdx_[k].size() *
es);
245 std::vector<std::vector<char>>
sbuf(recvRanks_.size());
247 for (std::size_t k = 0; k < recvRanks_.size(); ++k) {
248 sbuf[k].resize(recvIdx_[k].size() *
es);
249 for (std::size_t
i = 0;
i < recvIdx_[k].size(); ++
i)
250 field.pack(recvIdx_[k][
i],
sbuf[k].data() +
i *
es);
255 for (std::size_t
done = 0;
done < sendRanks_.size(); ++
done) {
260 for (std::size_t
i = 0;
i < sendIdx_[k].size(); ++
i)
261 field.addFrom(sendIdx_[k][
i],
rbuf[k].data() +
i *
es);
279 t.sendRanks = std::vector<int>(sendRanks_.begin(), sendRanks_.end());
280 t.recvRanks = std::vector<int>(recvRanks_.begin(), recvRanks_.end());
281 for (
const auto&
v : sendIdx_) {
282 t.sendCounts.push_back(
static_cast<int>(
v.size()));
283 t.sendIdx.insert(
t.sendIdx.end(),
v.begin(),
v.end());
285 for (
const auto&
v : recvIdx_) {
286 t.recvCounts.push_back(
static_cast<int>(
v.size()));
287 t.recvIdx.insert(
t.recvIdx.end(),
v.begin(),
v.end());
289 t.selfSrc = selfSrc_;
290 t.selfDst = selfDst_;
299 for (
auto&
v : recvIdx_)
312 void freeGraphComm() {
331 persistentReady_ =
false;
334 void buildRecvLookup() {
335 recvRankPos_.clear();
336 for (std::size_t k = 0; k < recvRanks_.size(); ++k)
337 recvRankPos_[recvRanks_[k]] = k;
340 template <
typename Field>
341 void applySelfCopy(
Field& field) {
344 if (selfSrc_.empty())
346 std::vector<char> tmp(field.bytesPerElem());
347 for (std::size_t
i = 0;
i < selfSrc_.size(); ++
i) {
348 field.pack(selfSrc_[
i], tmp.data());
349 field.unpack(selfDst_[
i], tmp.data());
353 void ensureGraphComm(std::size_t
es) {
354 if (persistentReady_ && graphElemSize_ ==
es)
360 std::vector<int>
sources(recvRanks_.begin(), recvRanks_.end());
361 std::vector<int>
dests(sendRanks_.begin(), sendRanks_.end());
368 graphSendCnt_.resize(
dests.size());
369 graphSendDispl_.resize(
dests.size());
371 for (std::size_t k = 0; k <
dests.size(); ++k) {
372 graphSendCnt_[k] =
static_cast<int>(sendIdx_[k].size() *
es);
373 graphSendDispl_[k] = off;
374 off += graphSendCnt_[k];
376 graphSendBuf_.resize(off);
378 graphRecvCnt_.resize(
sources.size());
379 graphRecvDispl_.resize(
sources.size());
381 for (std::size_t k = 0; k <
sources.size(); ++k) {
382 graphRecvCnt_[k] =
static_cast<int>(recvIdx_[k].size() *
es);
383 graphRecvDispl_[k] = off;
384 off += graphRecvCnt_[k];
386 graphRecvBuf_.resize(off);
389 persistentReady_ =
true;
394 decomp::BlockIndexer<Dim> indexer_;
397 std::vector<int> sendRanks_;
398 std::vector<std::vector<Index>> sendIdx_;
399 std::vector<int> recvRanks_;
400 std::vector<std::vector<Index>> recvIdx_;
401 std::vector<std::vector<Index>> recvGlob_;
402 std::map<int, std::size_t> recvRankPos_;
403 std::vector<Index> selfSrc_, selfDst_;
406 std::vector<MPI_Request> sendReqs_, recvReqs_;
407 std::vector<std::vector<char>> sendBufs_, recvBufs_;
412 bool persistentReady_ =
false;
413 std::size_t graphElemSize_ = 0;
414 std::vector<int> graphSendCnt_, graphSendDispl_, graphRecvCnt_, graphRecvDispl_;
415 std::vector<char> graphSendBuf_, graphRecvBuf_;
void start(Field &field, int tag=0)
Post all sends/recvs; returns immediately so the caller can compute the block interior.
void reverseAdd(Field &field, int tag=0)
void buildTopology(const decomp::BlockDecomposer< Dim > &dec, int rank, int ghostWidth, const std::array< bool, Dim > &periodic, MPI_Comm comm=MPI_COMM_WORLD)
Build the halo topology for rank's block of dec, with the given ghost width and per-axis periodicity.
const decomp::BlockIndexer< Dim > & indexer() const
void exchangeNbx(Field &field, int tag=0)
Convenience: full blocking exchange via the NBX-style engine (start + wait).
void wait(Field &field)
Complete a started exchange: wait for receives and scatter them into the ghost cells.
GridHaloTopology(const GridHaloTopology &)=delete
std::size_t numGhostRecv() const
FlatTopology flatten() const
GridHaloTopology & operator=(const GridHaloTopology &)=delete
std::size_t numNeighbors() const
void exchangePersistent(Field &field)
Full exchange via MPI_Neighbor_alltoallv on a cached distributed-graph communicator.
GridHaloTopology()=default
int MPI_Waitall(int, MPI_Request *, MPI_Status *)
int MPI_Comm_free(MPI_Comm *)
#define MPI_STATUS_IGNORE
#define MPI_STATUSES_IGNORE
int MPI_Waitany(int, MPI_Request *, int *idx, MPI_Status *)
int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
int MPI_Finalized(int *f)
int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
int MPI_Neighbor_alltoallv(const void *, const int *, const int *, MPI_Datatype, void *, const int *, const int *, MPI_Datatype, MPI_Comm)
int MPI_Dist_graph_create_adjacent(MPI_Comm c, int, const int *, const int *, int, const int *, const int *, MPI_Info, int, MPI_Comm *out)
Index wrap(Index x, Index n)
Periodic wrap of a coordinate into [0, n): wrap(x, n) = (x % n + n) % n.
Kokkos::View< T *, MemSpace > View
1D device array.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
A contiguous local array of T (one per cell of the extended block) viewed as a packable field.
void addFrom(Index localIdx, const char *src)
void pack(Index localIdx, char *dst) const
void unpack(Index localIdx, const char *src)
std::size_t bytesPerElem() const
std::vector< int > recvCounts
std::vector< int > sendRanks
std::vector< int > sendCounts
std::vector< Index > recvIdx
std::vector< int > recvRanks
std::vector< Index > selfSrc
std::vector< Index > selfDst
std::vector< Index > sendIdx