13#ifndef PECLET_CORE_HALO_PARTICLE_MIGRATOR_HPP
14#define PECLET_CORE_HALO_PARTICLE_MIGRATOR_HPP
56 for (
int i = 0;
i <
Dim; ++
i) {
57 double rel = (x[
i] - map_.origin[
i]) / map_.cellSize[
i];
59 if (map_.periodic[
i]) {
62 c = std::clamp<Index>(c, 0,
gsize[
i] - 1);
75 for (
int i = 0;
i <
Dim; ++
i) {
76 if (!map_.periodic[
i])
78 double L = map_.cellSize[
i] *
static_cast<double>(
gsize[
i]);
79 double rel = x[
i] - map_.origin[
i];
80 rel = std::fmod(std::fmod(
rel,
L) +
L,
L);
81 x[
i] = map_.origin[
i] +
rel;
90 const std::size_t n =
pos.size();
94 std::map<int, std::vector<char>>
outbox;
97 for (std::size_t
i = 0;
i < n; ++
i) {
100 if (owner == rank_) {
107 std::size_t off =
buf.size();
119 std::vector<std::pair<int, const std::vector<char>*>>
queue;
127 auto packNext = [&](std::vector<char>&
out) ->
int {
135 auto onRecv = [&](
int , std::vector<char>&
msg) {
137 for (std::size_t
i = 0;
i <
cnt; ++
i) {
143 std::size_t off =
payload.size();
157 int rank()
const {
return rank_; }
164 const auto&
o = dec_->origins()[r];
165 const auto& s = dec_->sizes()[r];
168 for (
int i = 0;
i <
Dim; ++
i) {
169 double lo = map_.origin[
i] +
o[
i] * map_.cellSize[
i];
170 double hi = map_.origin[
i] + (
o[
i] + s[
i]) * map_.cellSize[
i];
171 double L = map_.cellSize[
i] *
static_cast<double>(
gsize[
i]);
175 if (map_.periodic[
i]) {
179 double bestGap = std::numeric_limits<double>::infinity();
181 for (
int c = 0; c < nc; ++c) {
183 double gap = (p <
lo) ? (
lo - p) : (p >
hi) ? (p -
hi) : 0.0;
207 const auto&
o = dec_->origins()[r];
208 const auto& s = dec_->sizes()[r];
211 for (
int d = 0;
d <
Dim; ++
d) {
212 const double lo = map_.origin[
d] +
o[
d] * map_.cellSize[
d];
213 const double hi = map_.origin[
d] + (
o[
d] + s[
d]) * map_.cellSize[
d];
214 auto gap = [&](
double shift) {
215 const double a =
bmin[
d] + shift, b =
bmax[
d] + shift;
216 return std::max(0.0, std::max(
lo - b, a -
hi));
219 if (map_.periodic[
d]) {
220 const double L = map_.cellSize[
d] *
static_cast<double>(
gsize[
d]);
221 g = std::min(g, std::min(gap(-
L), gap(
L)));
230 const auto&
o = dec_->origins()[r];
231 const auto& s = dec_->sizes()[r];
235 for (
int d = 0;
d <
Dim; ++
d) {
236 lo[
d] = map_.origin[
d] +
o[
d] * map_.cellSize[
d];
237 hi[
d] = map_.origin[
d] + (
o[
d] + s[
d]) * map_.cellSize[
d];
238 const double L = map_.cellSize[
d] *
static_cast<double>(
gsize[
d]);
241 if (map_.periodic[
d]) {
256 for (
int d = 0;
d <
Dim; ++
d) {
258 for (
int k = 0;
k < nc[
d]; ++
k) {
259 const double p = x[
d] +
cand[
d][
k];
260 const double gap = (p <
lo[
d]) ? (
lo[
d] - p) : (p >
hi[
d]) ? (p -
hi[
d]) : 0.0;
261 if (gap * gap <
rc2) {
271 for (
int d = 0;
d <
Dim; ++
d)
273 for (
int idx = 0; idx <
total; ++idx) {
278 for (
int d = 0;
d <
Dim; ++
d) {
279 const int j =
t %
nk[
d];
308 std::map<int, std::vector<char>>
outbox;
310 for (std::size_t
i = 0;
i <
pos.size(); ++
i) {
311 for (
int r = 0; r <
nranks; ++r) {
317 std::size_t off =
buf.size();
325 std::vector<std::pair<int, const std::vector<char>*>>
queue;
328 queue.emplace_back(
kv.first, &
kv.second);
329 std::size_t
q = 0,
recv = 0;
331 auto packNext = [&](std::vector<char>&
out) ->
int {
339 auto onRecv = [&](
int , std::vector<char>&
msg) {
341 for (std::size_t
i = 0;
i <
cnt; ++
i) {
363 std::size_t sent_ = 0, received_ = 0;
Orthogonal recursive bisection of a Dim-dimensional global cell grid into numBlocks axis-aligned bloc...
IVec< Dim > cellOf(const Vec< Dim > &x) const
Global decomposition cell containing position x (after periodic wrap / boundary clamp).
std::size_t gatherGhosts(const std::vector< Vec< Dim > > &pos, const std::vector< char > &payload, std::size_t stride, double rcut, std::vector< Vec< Dim > > &ghostPos, std::vector< char > &ghostPayload)
Gather ghost copies of particles within rcut of this rank's block boundary.
const decomp::BlockDecomposer< Dim > & decomposer() const
std::size_t lastReceived() const
Vec< Dim > wrapPosition(Vec< Dim > x) const
Wrap a position into the periodic box (no-op on non-periodic axes).
std::size_t migrate(std::vector< Vec< Dim > > &pos, std::vector< char > &payload, std::size_t stride)
Reassign every particle to its owning rank.
bool boxWithinRcutOfBlock(const Vec< Dim > &bmin, const Vec< Dim > &bmax, int r, double rcut) const
Append the shift (= image − x) of EVERY periodic image of x that comes within rcut of block r's AABB ...
void imagesWithinRcutOfBlock(const Vec< Dim > &x, int r, double rcut, bool allowIdentity, std::vector< Vec< Dim > > &outShifts) const
bool withinRcutOfBlock(const Vec< Dim > &x, int r, double rcut, Vec< Dim > &img) const
True if x (via its closest periodic image) comes within rcut of block r's physical AABB.
void init(const decomp::BlockDecomposer< Dim > &dec, int rank, DomainMap< Dim > map, MPI_Comm comm=MPI_COMM_WORLD)
int ownerOf(const Vec< Dim > &x) const
Rank that owns the block containing position x (after periodic wrap / boundary clamp).
std::size_t lastSent() const
int MPI_Comm_size(MPI_Comm, int *s)
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).
Physical-space layout that maps a position to a global cell of the decomposition.
Vec< Dim > origin
physical coordinate of global cell (0,...)
std::array< bool, Dim > periodic
per-axis periodicity
Vec< Dim > cellSize
physical size of one global cell