21#ifndef PECLET_CORE_HALO_PARTICLE_HALO_TOPOLOGY_HPP
22#define PECLET_CORE_HALO_PARTICLE_HALO_TOPOLOGY_HPP
52 void build(
const std::vector<
Vec<Dim>>& pos,
double rcut,
bool includePeriodicSelf =
false) {
53 numOwned_ = pos.size();
56 const int me = mig_->rank();
59 std::map<int, std::vector<Index>> sendMap;
60 std::map<int, std::vector<Vec<Dim>>> shiftMap;
62 for (std::size_t i = 0; i < pos.size(); ++i) {
63 for (
int r = 0; r < nranks; ++r) {
66 if (!mig_->withinRcutOfBlock(pos[i], r, rcut, img))
69 for (
int d = 0; d < Dim; ++d)
70 shift[d] = img[d] - pos[i][d];
71 sendMap[r].push_back(
static_cast<Index>(i));
72 shiftMap[r].push_back(shift);
78 for (
auto& [r, idx] : sendMap) {
79 sendRankPos_[r] = sendRanks_.size();
80 sendRanks_.push_back(r);
81 sendIdx_.push_back(std::move(idx));
91 auto packNext = [&](std::vector<char>& out) ->
int {
92 if (k >= sendRanks_.size())
94 int dst = sendRanks_[k];
95 auto& sh = shiftMap[dst];
97 out.resize(sh.size() *
sizeof(
Vec<Dim>));
98 std::memcpy(out.data(), sh.data(), out.size());
101 auto onRecv = [&](
int src, std::vector<char>& msg) {
102 int cnt =
static_cast<int>(msg.size() /
sizeof(
Vec<Dim>));
103 recvRankPos_[src] = recvRanks_.size();
104 recvRanks_.push_back(src);
105 recvCount_.push_back(cnt);
107 for (
int i = 0; i < cnt; ++i)
108 shift_.push_back(sh[i]);
110 nbx.
exchange(packNext, onRecv, 7501);
112 recvOffset_.assign(recvRanks_.size() + 1, 0);
113 for (std::size_t i = 0; i < recvCount_.size(); ++i)
114 recvOffset_[i + 1] = recvOffset_[i] + recvCount_[i];
115 numReceived_ = shift_.size();
122 if (includePeriodicSelf) {
123 std::vector<Vec<Dim>> imgs;
124 for (std::size_t i = 0; i < pos.size(); ++i) {
126 mig_->imagesWithinRcutOfBlock(pos[i], me, rcut,
false, imgs);
127 for (
const auto& sh : imgs) {
128 selfIdx_.push_back(
static_cast<Index>(i));
129 selfShift_.push_back(sh);
133 for (
const auto& sh : selfShift_)
134 shift_.push_back(sh);
135 numGhost_ = shift_.size();
138 ghostPos_.assign(numGhost_,
Vec<Dim>{});
150 forwardDirect<Vec<Dim>>(owned, 7502, [&](std::size_t p,
const Vec<Dim>* in) {
151 Index off = recvOffset_[p];
152 for (
int i = 0; i < recvCount_[p]; ++i)
153 for (
int d = 0; d < Dim; ++d)
154 ghost[off + i][d] = in[i][d] + shift_[off + i][d];
157 for (std::size_t j = 0; j < selfIdx_.size(); ++j)
158 for (
int d = 0; d < Dim; ++d)
159 ghost[numReceived_ + j][d] = owned[selfIdx_[j]][d] + shift_[numReceived_ + j][d];
163 template <
typename T>
165 forwardDirect<T>(owned, 7503, [&](std::size_t p,
const T* in) {
166 Index off = recvOffset_[p];
167 for (
int i = 0; i < recvCount_[p]; ++i)
168 ghost[off + i] = in[i];
171 for (std::size_t j = 0; j < selfIdx_.size(); ++j)
172 ghost[numReceived_ + j] = owned[selfIdx_[j]];
177 template <
typename T>
181 const int ns =
static_cast<int>(sendRanks_.size());
182 const int nr =
static_cast<int>(recvRanks_.size());
183 std::vector<std::vector<T>> rbuf(ns), sbuf(nr);
185 for (
int k = 0; k < ns; ++k) {
186 rbuf[k].resize(sendIdx_[k].size());
187 MPI_Irecv(rbuf[k].data(),
static_cast<int>(rbuf[k].size() *
sizeof(T)),
MPI_BYTE,
188 sendRanks_[k], 7504, mig_->comm(), &rreq[k]);
190 for (
int p = 0; p < nr; ++p) {
191 Index off = recvOffset_[p];
192 sbuf[p].assign(ghost + off, ghost + off + recvCount_[p]);
193 MPI_Isend(sbuf[p].data(),
static_cast<int>(sbuf[p].size() *
sizeof(T)),
MPI_BYTE,
194 recvRanks_[p], 7504, mig_->comm(), &sreq[p]);
197 for (
int k = 0; k < ns; ++k) {
198 auto& idx = sendIdx_[k];
199 for (std::size_t i = 0; i < idx.size(); ++i)
200 owned[idx[i]] += rbuf[k][i];
203 for (std::size_t j = 0; j < selfIdx_.size(); ++j)
204 owned[selfIdx_[j]] += ghost[numReceived_ + j];
212 template <
typename T,
typename Store>
213 void forwardDirect(
const T* owned,
int tag, Store&& store) {
214 const int ns =
static_cast<int>(sendRanks_.size());
215 const int nr =
static_cast<int>(recvRanks_.size());
216 std::vector<std::vector<T>> sbuf(ns), rbuf(nr);
218 for (
int p = 0; p < nr; ++p) {
219 rbuf[p].resize(recvCount_[p]);
220 MPI_Irecv(rbuf[p].data(),
static_cast<int>(rbuf[p].size() *
sizeof(T)),
MPI_BYTE,
221 recvRanks_[p], tag, mig_->comm(), &rreq[p]);
223 for (
int k = 0; k < ns; ++k) {
224 auto& idx = sendIdx_[k];
225 sbuf[k].resize(idx.size());
226 for (std::size_t i = 0; i < idx.size(); ++i)
227 sbuf[k][i] = owned[idx[i]];
228 MPI_Isend(sbuf[k].data(),
static_cast<int>(sbuf[k].size() *
sizeof(T)),
MPI_BYTE,
229 sendRanks_[k], tag, mig_->comm(), &sreq[k]);
232 for (
int p = 0; p < nr; ++p)
233 store(
static_cast<std::size_t
>(p), rbuf[p].data());
261 for (
const auto& idx : sendIdx_) {
262 t.
sendCounts.push_back(
static_cast<int>(idx.size()));
270 recvOffset_.begin() +
static_cast<std::ptrdiff_t
>(recvRanks_.size()));
279 std::size_t numOwned_ = 0, numGhost_ = 0;
282 std::vector<int> sendRanks_;
283 std::vector<std::vector<Index>> sendIdx_;
284 std::map<int, std::size_t> sendRankPos_;
287 std::vector<int> recvRanks_;
288 std::vector<int> recvCount_;
289 std::vector<Index> recvOffset_;
290 std::map<int, std::size_t> recvRankPos_;
294 std::vector<Index> selfIdx_;
295 std::vector<Vec<Dim>> selfShift_;
296 std::size_t numReceived_ = 0;
298 std::vector<Vec<Dim>>
300 std::vector<Vec<Dim>> ghostPos_;
void exchange(PackNext &&packNext, OnRecv &&onRecv, int tag=0)
void init(const ParticleMigrator< Dim > &mig)
Bind to a migrator (provides the decomposition, domain map, rank and comm).
void forwardPositions(const Vec< Dim > *owned, Vec< Dim > *ghost)
owned[N] -> ghost[G], with the periodic image shift added (use for positions).
void forward(const T *owned, T *ghost)
owned[N] -> ghost[G], verbatim (translation-invariant fields: velocity, id, radius,...
std::size_t numOwned() const
void build(const std::vector< Vec< Dim > > &pos, double rcut, bool includePeriodicSelf=false)
(Re)establish the owner<->ghost correspondence: every owned particle within rcut of another rank's bl...
void reverse(const T *ghost, T *owned)
ghost[G] -> owned[N], accumulated (T must have operator+=).
const std::vector< Vec< Dim > > & ghostPositions() const
std::size_t numGhost() const
int MPI_Comm_size(MPI_Comm, int *s)
int MPI_Waitall(int, MPI_Request *, MPI_Status *)
#define MPI_STATUSES_IGNORE
int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
std::array< Real, Dim > Vec
Multi-dimensional real vector.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
std::vector< Vec< Dim > > shift
std::vector< int > sendOffsets
std::vector< int > recvRanks
std::vector< Index > sendIdx
std::vector< int > sendCounts
std::vector< Index > recvOffsets
std::vector< int > recvCounts
std::vector< Index > selfIdx
std::vector< int > sendRanks