37#ifndef PECLET_CORE_AMR_DISTRIBUTED_FLOW_MG_HPP
38#define PECLET_CORE_AMR_DISTRIBUTED_FLOW_MG_HPP
40#ifdef PECLET_CORE_HAVE_MORTON
64 double sx = 0.0,
sv = 0.0;
65 Kokkos::parallel_reduce(
66 "amr::fv_rmean", op.
n,
72 an +=
u(
i) / invVol(
i);
73 ad += 1.0 / invVol(
i);
92template <
int Dim,
unsigned Bits = (Dim == 2 ? 32u : (Dim == 3 ? 21u : 16u))>
98 using M =
typename Octree::M;
99 using Code =
typename Octree::Code;
110 template <
class OpenFn>
117 levels_[0]->ap.buildOpenness(
openFn);
118 for (std::size_t
L = 0;
L + 1 < levels_.size(); ++
L)
119 coarsenOpennessTo(
L);
125 std::size_t
numLevels()
const {
return levels_.size(); }
130 const FvOp&
op(std::size_t
L = 0)
const {
return levels_[
L]->op; }
142 Level&
lv = *levels_[
L];
144 if (
L + 1 == levels_.size()) {
146 lv.ex.exchange(
lv.x);
153 for (
int s = 0;
s < pre; ++
s) {
154 lv.ex.exchange(
lv.x);
157 lv.ex.exchange(
lv.x);
159 Level&
cl = *levels_[
L + 1];
161 Kokkos::deep_copy(
cl.x, 0.0);
164 for (
int s = 0;
s < post; ++
s) {
165 lv.ex.exchange(
lv.x);
180 Index n = 0, nExt = 0;
183 std::vector<Index> c2pHost;
186 void buildImpl(
const DO&
finest,
double h0,
const LeafHalo<Dim, Bits>*
shared0) {
192 auto l0 = std::make_unique<Level>();
194 levels_.push_back(std::move(
l0));
196 Octree c = levels_.back()->d.local();
201 auto lv = std::make_unique<Level>();
202 lv->d = levels_.back()->d;
203 lv->d.local() = std::move(
c);
204 levels_.push_back(std::move(
lv));
205 if (levels_.back()->d.local().numLeaves() == 1)
211 int nl =
static_cast<int>(levels_.size()),
gnl =
nl;
213 while (
static_cast<int>(levels_.size()) <
gnl) {
214 auto lv = std::make_unique<Level>();
215 lv->d = levels_.back()->d;
216 levels_.push_back(std::move(
lv));
223 std::array<long, Dim> shift{};
224 for (
int a = 0;
a < Dim; ++
a)
225 shift[
a] =
finest.blockFineOrigin()[
a];
228 for (
auto&
lvp : levels_) {
230 lv.n =
lv.d.local().numLeaves();
231 lv.ap.init(
lv.d.local(), h0_);
233 lv.ap.setFrameShift(shift);
236 std::vector<std::array<long, Dim>>
glo(
static_cast<std::size_t
>(
h.numGhosts()));
237 std::vector<unsigned>
glv(
static_cast<std::size_t
>(
h.numGhosts()));
238 for (
Index g = 0; g <
h.numGhosts(); ++g) {
239 for (
int a = 0;
a < Dim; ++
a)
240 glo[
static_cast<std::size_t
>(g)][
a] =
241 static_cast<long>(
h.ghostCoord(g)[
a]) - shift[
a];
242 glv[
static_cast<std::size_t
>(g)] =
static_cast<unsigned>(
h.level(
h.numLocal() + g));
244 lv.ap.setGhosts(std::move(
glo), std::move(
glv));
250 lv.ap.setResolver([
shared0, shift](
const std::array<long, Dim>& p) ->
Index {
251 std::array<long, Dim> g = p;
252 for (
int a = 0;
a < Dim; ++
a)
254 return shared0->lookupGlobal(g);
260 LeafHalo<Dim, Bits>* hp = &
lv.halo;
261 lv.ap.setResolver([hp, shift](
const std::array<long, Dim>& p) ->
Index {
262 std::array<long, Dim> g = p;
263 for (
int a = 0;
a < Dim; ++
a)
265 return hp->resolveGlobal(g);
274 lv.ap.forEachFaceNeighbor(
i, [](
Index,
Real,
int,
double) {});
275 if (
lv.halo.resolveMisses() == 0)
280 lv.nExt =
lv.hp->extendedSize();
285 for (std::size_t
L = 0;
L + 1 < levels_.size(); ++
L) {
286 const Octree&
f = levels_[
L]->d.local();
287 const Octree&
c = levels_[
L + 1]->d.local();
288 const Index nf =
f.numLeaves(), nc =
c.numLeaves();
289 std::vector<Index>& c2p = levels_[
L]->c2pHost;
290 c2p.assign(
static_cast<std::size_t
>(
nf), -1);
291 std::vector<Index>
cnt(
static_cast<std::size_t
>(nc), 0);
294 c2p[
static_cast<std::size_t
>(
i)] = p;
296 ++
cnt[
static_cast<std::size_t
>(p)];
298 std::vector<Index> start(
static_cast<std::size_t
>(nc) + 1, 0);
299 for (
Index p = 0; p < nc; ++p)
300 start[
static_cast<std::size_t
>(p) + 1] =
301 start[
static_cast<std::size_t
>(p)] +
cnt[
static_cast<std::size_t
>(p)];
302 std::vector<Index> idx(
static_cast<std::size_t
>(start[
static_cast<std::size_t
>(nc)]));
303 std::vector<Index>
cur(start.begin(), start.end() - 1);
305 const Index p = c2p[
static_cast<std::size_t
>(
i)];
307 idx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(p)]++)] =
i;
309 levels_[
L]->c2p =
toDevice(c2p,
"dfmg_c2p");
310 levels_[
L]->childStart =
toDevice(start,
"dfmg_cstart");
311 levels_[
L]->childIdx =
toDevice(idx,
"dfmg_cidx");
319 void coarsenOpennessTo(std::size_t
L) {
320 const Octree&
f = levels_[
L]->d.local();
321 const Octree&
c = levels_[
L + 1]->d.local();
323 const int F = 2 * Dim;
324 const Index nc =
c.numLeaves();
325 const Index ngc = levels_[
L + 1]->hp->numGhosts();
326 std::vector<double>
ca(
static_cast<std::size_t
>(nc +
ngc) *
F, 0.0);
327 std::vector<int>
cnt(
static_cast<std::size_t
>(nc) *
F, 0);
328 const std::vector<Index>& c2p = levels_[
L]->c2pHost;
329 for (
Index i = 0;
i <
f.numLeaves(); ++
i) {
330 const Index p = c2p[
static_cast<std::size_t
>(
i)];
333 const std::size_t base =
static_cast<std::size_t
>(p) *
F;
334 if (
c.level(p) ==
f.level(
i)) {
335 for (
int axis = 0; axis < Dim; ++axis)
336 for (
int dir = -1; dir <= 1; dir += 2) {
338 ca[base +
static_cast<std::size_t
>(
fi)] +=
capL.faceOpenness(
i, axis, dir);
339 cnt[base +
static_cast<std::size_t
>(
fi)] += 1;
342 const unsigned oct = M::from_code(
f.code(
i)).child_index(
f.level(
i));
343 for (
int axis = 0; axis < Dim; ++axis) {
344 const int dir = ((
oct >> axis) & 1) ? +1 : -1;
346 ca[base +
static_cast<std::size_t
>(
fi)] +=
capL.faceOpenness(
i, axis, dir);
347 cnt[base +
static_cast<std::size_t
>(
fi)] += 1;
354 const LeafHalo<Dim, Bits>&
h = *levels_[
L + 1]->hp;
355 std::vector<double> col(
static_cast<std::size_t
>(levels_[
L + 1]->nExt), 0.0);
356 for (
int fi = 0;
fi <
F; ++
fi) {
358 col[
static_cast<std::size_t
>(
i)] =
ca[
static_cast<std::size_t
>(
i) *
F +
fi];
361 ca[
static_cast<std::size_t
>(nc + g) *
F +
fi] =
362 col[
static_cast<std::size_t
>(nc + g)];
364 levels_[
L + 1]->ap.setOpennessRaw(std::move(
ca));
370 for (
auto&
lvp : levels_) {
372 auto A =
lv.ap.assembleFv();
374 lv.op.invVol =
toDevice(A.invVol,
"dfmg_invvol");
375 lv.op.faceStart =
toDevice(A.start,
"dfmg_start");
383 Kokkos::deep_copy(
lv.x, 0.0);
384 Kokkos::deep_copy(
lv.b, 0.0);
390 std::array<long, Dim> shift_{};
391 std::vector<std::unique_ptr<Level>> levels_;
392 bool removeMean_ =
false;
static int faceIndex(int axis, int dir)
DistributedOctree< Dim, Bits > DO
AmrPoisson< Dim, Bits > Poisson
const LeafHalo< Dim, Bits > & halo(std::size_t L=0) const
void sync(std::size_t L, View< double > v) const
Refresh the ghost tail of a level-L vector (the PCG matvec hook uses level 0).
std::size_t numLevels() const
void setRemoveMean(bool on)
View< double > x(std::size_t L=0)
Index extendedSize(std::size_t L=0) const
typename Octree::Code Code
void vcycle(int pre=2, int post=2, int bottom=40, double omega=0.8, std::size_t L=0)
One V-cycle on level L (correction scheme), the distributed mirror of Multigrid::vcycle: ghost refres...
const FvOp & op(std::size_t L=0) const
void build(const DO &finest, double h0, OpenFn &&openFn, const LeafHalo< Dim, Bits > *shared0=nullptr)
Build with cut-cell openness openFn(faceCentreWorld, axis) → [0,1] on the flow's distributed octree (...
const Poisson & poisson(std::size_t L=0) const
typename DO::Octree Octree
View< double > b(std::size_t L=0)
Index numLeaves(std::size_t L=0) const
BlockOctree< Dim, Bits > Octree
Device-resident value refresh over a finalized LeafHalo: pack the owner's local values as a Kokkos ke...
int MPI_Allreduce(const void *sbuf, void *rbuf, int count, MPI_Datatype dt, MPI_Op, MPI_Comm)
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 removeMeanFvDist(const FvOp &op, View< double > u, MPI_Comm comm)
removeMeanFv with the two mean sums folded across ranks (identical kernels; the Allreduce sits betwee...
std::vector< std::array< double, Dim > > transferFieldGradients(const BlockOctree< Dim, Bits > &oldT, const std::vector< double > &oldF)
Per-old-leaf minmod prolongation gradients (per fine-coordinate unit) — transferField's stencil,...
void jacobiFv(const FvOp &op, View< double > u, View< const double > rhs, View< double > tmp, double omega)
One weighted-Jacobi sweep of H u = rhs (in place).
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).
void residualFv(const FvOp &op, View< const double > u, View< const double > rhs, View< double > res)
res = rhs − H u.
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.
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
View< double > invVol
1/V_i, size n
View< double > faceW
w_f = openness·A_f/d_f per face, size nFaces
View< Index > faceStart
CSR row offsets, size n+1.
View< double > bcDiag
Dirichlet boundary diagonal per cell (0 if periodic), size n.