26#ifndef PECLET_CORE_AMR_MULTIGRID_HPP
27#define PECLET_CORE_AMR_MULTIGRID_HPP
29#ifdef PECLET_CORE_HAVE_MORTON
49 const Index a = childStart(p),
z = childStart(p + 1);
52 s +=
fine(childIdx(k));
53 coarse(p) = (
z >
a) ?
s /
static_cast<double>(
z -
a) : 0.0;
68 const Index a = childStart(p),
z = childStart(p + 1);
69 double sw = 0.0,
swv = 0.0;
72 const double w = kappa(
ch);
109 Kokkos::parallel_for(
116template <
int Dim,
unsigned Bits = (Dim == 2 ? 32u : (Dim == 3 ? 21u : 16u))>
128 hmg_ = std::make_unique<AmrMultigrid<Dim, Bits>>();
137 template <
class OpenFn>
139 bool immersedWall =
false) {
140 hmg_ = std::make_unique<AmrMultigrid<Dim, Bits>>();
142 hmg_->setOpenness(std::forward<OpenFn>(
openFn));
143 hmg_->setPeriodic(periodic);
144 hmg_->setImmersedWall(immersedWall);
165 for (
auto&
lv : levels_) {
171 std::size_t
numLevels()
const {
return levels_.size(); }
176 const FvOp&
op(std::size_t
L = 0)
const {
return levels_[
L].op; }
184 Level&
lv = levels_[
L];
186 if (
L + 1 == levels_.size()) {
193 for (
int s = 0;
s < pre; ++
s)
196 Level&
cl = levels_[
L + 1];
202 Kokkos::deep_copy(
cl.x, 0.0);
205 for (
int s = 0;
s < post; ++
s)
218 Level&
lv = levels_[0];
219 Kokkos::deep_copy(b0true_,
lv.b);
227 Kokkos::parallel_for(
238 Kokkos::parallel_reduce(
239 "amr::quad_resnorm",
lv.n,
241 double rr = res(
i) -
dq(
i);
246 Kokkos::deep_copy(
lv.b, b0true_);
263 void buildFromHostMg() {
264 const std::size_t
nl = hmg_->numLevels();
267 for (std::size_t
L = 0;
L <
nl; ++
L) {
270 Level&
lv = levels_[
L];
271 lv.n =
oct.numLeaves();
275 std::vector<double>
kap(
static_cast<std::size_t
>(
lv.n));
278 for (
int axis = 0; axis < Dim; ++axis)
279 for (
int dir = -1; dir <= 1; dir += 2)
280 s +=
ap.faceOpenness(
i, axis, dir);
281 kap[
static_cast<std::size_t
>(
i)] =
s /
static_cast<double>(2 * Dim);
289 for (std::size_t
L = 0;
L + 1 <
nl; ++
L) {
290 const Octree&
f = hmg_->op(
L).octree();
291 const Octree&
c = hmg_->op(
L + 1).octree();
292 const Index nf =
f.numLeaves(), nc =
c.numLeaves();
293 std::vector<Index> c2p(
static_cast<std::size_t
>(
nf));
294 std::vector<Index>
cnt(
static_cast<std::size_t
>(nc), 0);
296 Code parent = M::from_code(
f.code(
i)).ancestor(
f.level(
i) + 1).code();
298 c2p[
static_cast<std::size_t
>(
i)] = p;
300 ++
cnt[
static_cast<std::size_t
>(p)];
302 std::vector<Index> start(
static_cast<std::size_t
>(nc) + 1, 0);
303 for (
Index p = 0; p < nc; ++p)
304 start[
static_cast<std::size_t
>(p) + 1] =
305 start[
static_cast<std::size_t
>(p)] +
cnt[
static_cast<std::size_t
>(p)];
306 std::vector<Index> idx(
static_cast<std::size_t
>(
nf));
307 std::vector<Index>
cur(start.begin(), start.end() - 1);
309 Index p = c2p[
static_cast<std::size_t
>(
i)];
311 idx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(p)]++)] =
i;
313 levels_[
L].c2p =
toDevice(c2p,
"mg_c2p");
314 levels_[
L].childStart =
toDevice(start,
"mg_cstart");
315 levels_[
L].childIdx =
toDevice(idx,
"mg_cidx");
319 buildQuadCsr(hmg_->op(0), hmg_->op(0).octree());
333 const double c0 =
lv.op.c0, cD =
lv.op.cD;
334 BlockOctreeView<Dim, Bits> ov;
348 const std::size_t
nl = hmg_->numLevels();
349 for (std::size_t
L = 0;
L <
nl &&
L < levels_.size(); ++
L)
350 buildFaceCsr(hmg_->op(
L), hmg_->op(
L).octree(), levels_[
L]);
357 const Index n =
t.numLeaves();
358 std::vector<std::vector<std::pair<Index, double>>>
per(
static_cast<std::size_t
>(n));
359 const double h0 =
ap.h0();
361 const unsigned Li =
t.level(
i);
362 const double invV = 1.0 /
ap.cellVolume(
i);
364 const unsigned Lj =
t.level(
j);
374 std::vector<Index>
qs(
static_cast<std::size_t
>(n) + 1, 0);
376 qs[
static_cast<std::size_t
>(
i) + 1] =
377 qs[
static_cast<std::size_t
>(
i)] +
378 static_cast<Index>(
per[
static_cast<std::size_t
>(
i)].size());
379 const Index nq =
qs[
static_cast<std::size_t
>(n)];
380 std::vector<Index>
slot(
static_cast<std::size_t
>(
nq));
381 std::vector<double> coef(
static_cast<std::size_t
>(
nq));
385 slot[
static_cast<std::size_t
>(k)] =
e.first;
386 coef[
static_cast<std::size_t
>(k)] =
e.second;
391 qCoef_ =
toDevice(coef,
"mg_qcoef");
403 const double sc =
static_cast<double>(
Index(1) <<
t.level(
coarse));
404 const double sf =
static_cast<double>(
Index(1) <<
t.level(
fine));
405 for (
int tt = 0;
tt < Dim; ++
tt) {
408 const double dt = ((
static_cast<double>(
bf[0][
tt]) + 0.5 *
sf) -
409 (
static_cast<double>(
bc[0][
tt]) + 0.5 *
sc)) *
413 if (
cp < 0 ||
cm < 0)
419 const double cUp =
dt / (2.0 *
H) + 0.5 *
dt *
dt / (
H *
H);
420 const double cUm = -
dt / (2.0 *
H) + 0.5 *
dt *
dt / (
H *
H);
431 std::unique_ptr<AmrMultigrid<Dim, Bits>> hmg_;
432 std::vector<Level> levels_;
433 bool kappaRestrict_ =
false;
434 bool removeMean_ =
false;
morton::Morton< Dim, Bits > M
typename M::code_type Code
void setRemoveMean(bool on)
Opt-in (default off): project the correction to mean-zero over fluid cells at every V-cycle level — t...
View< Index > quadSlot() const
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 (default finest) of the standard (consistent conservative) operator,...
void build(const Octree &finest, double h0, OpenFn &&openFn, bool periodic=true, bool immersedWall=false)
Build with cut-cell openness openFn(faceCentreWorld, axis) → [0,1], coarsened to every level by area-...
Code octreeCode(std::size_t L, Index i) const
BlockOctree< Dim, Bits > Octree
const FvOp & op(std::size_t L=0) const
View< double > x(std::size_t L=0)
void setKappaRestrict(bool on)
Opt-in: use κ-weighted (fluid-fraction) restriction instead of the default plain volume-average.
AmrPoisson< Dim, Bits > Poisson
double solveQuad(int outer=20, int cyclesPerOuter=1, int pre=2, int post=2, int bottom=40, double omega=0.8)
Solve L_quad u = rhs (the 2nd-order graded operator) by deferred correction: each outer step solves L...
Index numLeaves(std::size_t L=0) const
void reassembleOperators()
Re-assemble every level's operator ON THE DEVICE from the (host) hierarchy's current geometry — the d...
typename Octree::Code Code
void build(const Octree &finest, double h0)
Build + upload the hierarchy from a finest octree (uniform coarsening), openness- free.
View< Index > quadStart() const
void setHelmholtz(double c0, double cD)
Turn every level's operator into the Helmholtz form H = c0·I + cD·L (default c0=0,...
View< double > b(std::size_t L=0)
View< double > quadCoef() const
std::size_t numLevels() const
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 zeroMasked(View< double > v, View< const char > excl, Index n)
Zero v at excluded cells (excl != 0).
void removeMeanFv(const FvOp &op, View< double > u)
Project u to volume-weighted-mean-zero over the ACTIVE (fluid) cells of the operator — the constant-n...
void quadDelta(View< const Index > qStart, View< const Index > qSlot, View< const double > qCoef, View< const double > u, View< double > dq, Index n)
dq = (L_quad − L_std) u, the quadratic coarse-fine correction as its own SpMV over a precomputed CSR ...
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 restrictKappa(View< const Index > childStart, View< const Index > childIdx, View< const double > fine, View< const double > kappa, View< double > coarse, Index nCoarse)
Restrict, κ-weighted: coarse(p) = Σ_child κ_c·fine_c / Σ_child κ_c, with κ the fine cell's fluid-frac...
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.
void prolongAddMasked(View< const Index > c2p, View< const double > coarse, View< const char > excl, View< double > fine, Index nFine)
Masked piecewise-constant prolong + correct: fine(i) += coarse(c2p(i)) only on non-excluded fine cell...
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).