25#ifndef PECLET_CORE_AMR_DISTRIBUTED_VIEW_HPP
26#define PECLET_CORE_AMR_DISTRIBUTED_VIEW_HPP
28#ifdef PECLET_CORE_HAVE_MORTON
45template <
int Dim,
unsigned Bits>
50 void init(
const DO& d,
const typename DO::GatherHaloTopology&
t) {
53 nLocal_ =
static_cast<Index>(
t.localSlot.size());
54 nSend_ =
static_cast<Index>(
t.sendLeaf.size());
55 nRecv_ =
static_cast<Index>(
t.recvSlot.size());
56 d_localSlot_ =
toDevice(
t.localSlot,
"dgh::localSlot");
57 d_localLeaf_ =
toDevice(
t.localLeaf,
"dgh::localLeaf");
58 d_sendLeaf_ =
toDevice(
t.sendLeaf,
"dgh::sendLeaf");
59 d_recvSlot_ =
toDevice(
t.recvSlot,
"dgh::recvSlot");
60 sendRanks_ =
t.sendRanks;
61 sendCounts_ =
t.sendCounts;
62 recvRanks_ =
t.recvRanks;
63 recvCounts_ =
t.recvCounts;
64 sendOff_.assign(sendCounts_.size() + 1, 0);
65 for (std::size_t k = 0; k < sendCounts_.size(); ++k)
66 sendOff_[k + 1] = sendOff_[k] + sendCounts_[k];
67 recvOff_.assign(recvCounts_.size() + 1, 0);
68 for (std::size_t k = 0; k < recvCounts_.size(); ++k)
69 recvOff_[k + 1] = recvOff_[k] + recvCounts_[k];
70 d_sendBuf_ =
View<double>(Kokkos::view_alloc(
"dgh::sendBuf", Kokkos::WithoutInitializing),
71 static_cast<std::size_t
>(nSend_));
72 d_recvBuf_ =
View<double>(Kokkos::view_alloc(
"dgh::recvBuf", Kokkos::WithoutInitializing),
73 static_cast<std::size_t
>(nRecv_));
74 h_sendBuf_ = Kokkos::create_mirror_view(d_sendBuf_);
75 h_recvBuf_ = Kokkos::create_mirror_view(d_recvBuf_);
96 "dgh::local", Kokkos::RangePolicy<ExecSpace>(0, nLocal_),
102 Kokkos::parallel_for(
103 "dgh::pack", Kokkos::RangePolicy<ExecSpace>(0, nSend_),
106 Kokkos::deep_copy(h_sendBuf_, d_sendBuf_);
109 double*
sendBase =
aware ? d_sendBuf_.data() : h_sendBuf_.data();
110 double*
recvBase =
aware ? d_recvBuf_.data() : h_recvBuf_.data();
111 std::vector<MPI_Request>
reqs;
112 reqs.reserve(recvRanks_.size() + sendRanks_.size());
113 for (std::size_t k = 0; k < recvRanks_.size(); ++k) {
116 recvRanks_[k],
tag, comm_, &
reqs.back());
118 for (std::size_t k = 0; k < sendRanks_.size(); ++k) {
121 sendRanks_[k],
tag, comm_, &
reqs.back());
127 Kokkos::deep_copy(d_recvBuf_, h_recvBuf_);
130 Kokkos::parallel_for(
131 "dgh::scatter", Kokkos::RangePolicy<ExecSpace>(0, nRecv_),
139 Index nFaces_ = 0, nLocal_ = 0, nSend_ = 0, nRecv_ = 0;
140 IndexView d_localSlot_, d_localLeaf_, d_sendLeaf_, d_recvSlot_;
141 std::vector<int> sendRanks_, sendCounts_, sendOff_, recvRanks_, recvCounts_, recvOff_;
149template <
int Dim,
unsigned Bits = (Dim == 2 ? 32u : (Dim == 3 ? 21u : 16u))>
158 g_ =
View<double>(Kokkos::view_alloc(
"dpd::g", Kokkos::WithoutInitializing),
159 static_cast<std::size_t
>(n_) * (2 * Dim));
160 scratch_ =
View<double>(Kokkos::view_alloc(
"dpd::scratch", Kokkos::WithoutInitializing),
161 static_cast<std::size_t
>(n_));
170 const int F = 2 * Dim;
171 const double inv = 1.0 / (h0_ * h0_);
173 Kokkos::parallel_for(
176 for (
int f = 0;
f <
F; ++
f)
184 const int F = 2 * Dim;
185 const double inv = 1.0 / (h0_ * h0_), diag =
F *
inv;
189 Kokkos::parallel_for(
190 "dpd::jacobi_update", Kokkos::RangePolicy<ExecSpace>(0, n_),
200 Kokkos::parallel_reduce(
201 "dpd::residual", Kokkos::RangePolicy<ExecSpace>(0, n_),
203 double r = b(
i) -
ax(
i);
217 Kokkos::parallel_reduce(
218 "dpd::resnorm", Kokkos::RangePolicy<ExecSpace>(0, n_),
220 double r = b(
i) -
ax(
i);
241template <
int Dim,
unsigned Bits = (Dim == 2 ? 32u : (Dim == 3 ? 21u : 16u))>
247 const std::array<bool, Dim>& periodic,
MPI_Comm comm) {
254 auto lvl = std::make_unique<Level>();
257 lvl->d.init(g, 0,
lg, periodic, comm);
259 lvl->n =
lvl->d.local().numLeaves();
263 levels_.push_back(std::move(
lvl));
267 for (
int d = 0; d < Dim; ++d) {
268 if (g[d] % 2 != 0 || g[d] / 2 < 2)
281 for (std::size_t
L = 0;
L + 1 < levels_.size(); ++
L) {
282 auto&
fine = levels_[
L]->d;
283 auto&
coarse = levels_[
L + 1]->d;
286 std::vector<Index> c2p(
static_cast<std::size_t
>(
nf), -1);
287 std::vector<Index>
cnt(
static_cast<std::size_t
>(nc), 0);
290 for (
int d = 0; d < Dim; ++d)
293 c2p[
static_cast<std::size_t
>(
i)] = p;
295 ++
cnt[
static_cast<std::size_t
>(p)];
297 std::vector<Index> start(
static_cast<std::size_t
>(nc) + 1, 0);
298 for (
Index p = 0; p < nc; ++p)
299 start[
static_cast<std::size_t
>(p) + 1] =
300 start[
static_cast<std::size_t
>(p)] +
cnt[
static_cast<std::size_t
>(p)];
301 std::vector<Index> idx(
static_cast<std::size_t
>(start[
static_cast<std::size_t
>(nc)]));
302 std::vector<Index>
cur(start.begin(), start.end() - 1);
304 Index p = c2p[
static_cast<std::size_t
>(
i)];
306 idx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(p)]++)] =
i;
308 levels_[
L]->c2p =
toDevice(c2p,
"dmg::c2p");
309 levels_[
L]->childStart =
toDevice(start,
"dmg::cstart");
310 levels_[
L]->childIdx =
toDevice(idx,
"dmg::cidx");
314 std::size_t
numLevels()
const {
return levels_.size(); }
325 Level&
lv = *levels_[
L];
326 if (
L + 1 == levels_.size()) {
330 lv.op.jacobi(
x,
b, pre);
332 Level&
cl = *levels_[
L + 1];
335 Kokkos::deep_copy(
cl.x, 0.0);
338 lv.op.jacobi(
x,
b, post);
349 std::vector<std::unique_ptr<Level>> levels_;
Value-only, device-resident face-neighbour gather over a fixed topology (C2).
void init(const DO &d, const typename DO::GatherHaloTopology &t)
void gather(View< const double > x, View< double > g, int tag=41) const
g (size nFaces) := the face-neighbour values of x.
Device-resident distributed geometric multigrid for the plain Laplacian (the device analogue of the h...
View< double > x(std::size_t L=0)
Octree & octree(std::size_t L=0)
void vcycle(View< double > x, View< const double > b, int pre=2, int post=2, int bottom=30, std::size_t L=0)
One V-cycle of A x = b on level L (correction scheme); entirely device-resident bar the compact gathe...
View< double > b(std::size_t L=0)
DistributedPoissonView< Dim, Bits > & op(std::size_t L=0)
DistributedOctree< Dim, Bits > Octree
void build(const IVec< Dim > &g0, const AmrGeometry< Dim > &geo, const std::array< bool, Dim > &periodic, MPI_Comm comm)
Index numLeaves(std::size_t L=0) const
std::size_t numLevels() const
GatherHaloTopology buildGatherHaloTopology(const FaceGatherPlan &plan) const
Build the value-only gather topology from a FaceGatherPlan: classify each remote coord by owner (owne...
FaceGatherPlan buildFaceGatherPlan() const
Device-resident distributed plain-Laplacian Poisson operator: y = ∇²x with cross-block neighbours fro...
void jacobi(View< double > x, View< const double > b, int sweeps, double omega=0.8) const
sweeps damped-Jacobi relaxations of L u = b (in place). Reads only the previous iterate.
double residualNorm(View< const double > x, View< const double > b) const
double residual(View< const double > x, View< const double > b, View< double > res) const
res = b − L x (device); returns the global L2 norm (the only host scalar).
void apply(View< const double > x, View< double > y) const
y = L x (L = ∇², periodic).
void init(DistributedOctree< Dim, Bits > &d, double h0)
int MPI_Comm_size(MPI_Comm, int *s)
int MPI_Allreduce(const void *sbuf, void *rbuf, int count, MPI_Datatype dt, MPI_Op, MPI_Comm)
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 *)
void prolongAdd(View< const Index > c2p, View< const double > coarse, View< double > fine, Index nFine)
Prolong (piecewise-constant) + correct: fine(i) += coarse(c2p(i)).
void restrictField(View< const Index > childStart, View< const Index > childIdx, View< const double > fine, View< double > coarse, Index nCoarse)
Restrict: coarse(p) = mean over p's children (CSR fixed order ⇒ deterministic).
bool gpuAwareMpi()
Whether to hand DEVICE pointers straight to MPI (GPU-aware MPI) instead of host-staging.
View< T > toDevice(const std::vector< T > &h, const std::string &label)
Upload a host std::vector into a freshly-sized device View (empty vector => empty view).
Kokkos::View< T *, MemSpace > View
1D device array.
Kokkos::View< Index *, MemSpace > IndexView
Device array of grid/particle indices (the matched send/recv/self-copy lists).
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).