21#ifndef PECLET_AMR_VELOCITY_MG_HPP
22#define PECLET_AMR_VELOCITY_MG_HPP
34#include "peclet/core/common/view.hpp"
38template <
unsigned Bits = 21u>
57 const std::vector<double>& kappa,
const std::vector<char>& fluid,
63 const MomentumOp&
fineOp,
const std::vector<double>& kappa,
64 const std::vector<char>& fluid,
const std::vector<char>& cut,
Index minCoarse = 256) {
65 hmg_ = std::make_unique<AmrMultigrid<3, Bits>>();
70 hmg_->build(
finest, h0,
false);
71 std::size_t
nl = hmg_->numLevels();
72 while (
nl > 1 && hmg_->op(
nl - 1).octree().numLeaves() <
minCoarse)
78 std::vector<std::vector<double>>
kap(
nl);
80 for (std::size_t
L = 0;
L + 1 <
nl; ++
L) {
81 const Octree&
f = hmg_->op(
L).octree();
82 const Octree&
c = hmg_->op(
L + 1).octree();
84 std::vector<double>
ks(
static_cast<std::size_t
>(
nc), 0.0),
85 kn(
static_cast<std::size_t
>(
nc), 0.0);
87 Code par = M::from_code(
f.code(
i)).ancestor(
f.level(
i) + 1).code();
90 ks[
static_cast<std::size_t
>(
p)] +=
kap[
L][
static_cast<std::size_t
>(
i)];
91 kn[
static_cast<std::size_t
>(
p)] += 1.0;
95 ks[
static_cast<std::size_t
>(
p)] /=
96 (
kn[
static_cast<std::size_t
>(
p)] > 0 ?
kn[
static_cast<std::size_t
>(
p)] : 1.0);
97 kap[
L + 1] = std::move(
ks);
108 std::vector<char>
excl(fluid.size());
109 for (std::size_t
i = 0;
i < fluid.size(); ++
i)
110 excl[
i] = (!fluid[
i] || cut[
i]) ? 1 : 0;
112 allocScratch(levels_[0],
static_cast<Index>(fluid.size()));
115 std::vector<Index>
hs(
static_cast<std::size_t
>(
fineOp.n) + 1),
hn(
fineOp.faceNbr.extent(0));
116 auto ms = Kokkos::create_mirror_view(
fineOp.faceStart);
117 auto mn = Kokkos::create_mirror_view(
fineOp.faceNbr);
118 Kokkos::deep_copy(
ms,
fineOp.faceStart);
119 Kokkos::deep_copy(
mn,
fineOp.faceNbr);
120 for (std::size_t
i = 0;
i <
hs.size(); ++
i)
122 for (std::size_t
i = 0;
i <
hn.size(); ++
i)
124 levels_[0].col = greedyColoring(
hs,
hn,
fineOp.n);
127 for (std::size_t
L = 1;
L <
nl; ++
L)
128 buildStaircase(
L, idiag, mu,
kap[
L]);
131 for (std::size_t
L = 0;
L + 1 <
nl; ++
L)
135 std::size_t
numLevels()
const {
return levels_.size(); }
150 Level&
lv = levels_[
L];
152 if (
L + 1 == levels_.size()) {
162 Level&
cl = levels_[
L + 1];
164 Kokkos::deep_copy(
cl.x, 0.0);
184 multicolorGSMom(
lv.op,
lv.x,
bc,
lv.col, 1.0);
190 void allocScratch(Level&
lv,
Index n) {
198 void buildStaircase(std::size_t
L,
double idiag,
double mu,
const std::vector<double>&
kap) {
209 const double Ldom = ap.h0()[0] *
static_cast<double>(
oct.brick()[0] * (
Index(1) <<
oct.lmax()));
210 const double id = std::max(idiag, mu / (
Ldom *
Ldom));
211 std::vector<double> diag(
static_cast<std::size_t
>(n), 1.0);
212 std::vector<char> solid(
static_cast<std::size_t
>(n), 1);
213 std::vector<Index> start(
static_cast<std::size_t
>(n) + 1, 0);
214 std::vector<std::vector<std::pair<Index, double>>>
rows(
static_cast<std::size_t
>(n));
216 if (
kap[
static_cast<std::size_t
>(
i)] < 0.5)
218 solid[
static_cast<std::size_t
>(
i)] = 0;
223 for (
int a = 0;
a < 3; ++
a) {
224 const double Ha = ap.cellWidth(
i,
a);
228 for (
int axis = 0; axis < 3; ++axis)
229 for (
int dir = -1; dir <= 1; dir += 2) {
230 Index j = ap.periodicNeighbor(
i, axis, dir);
236 diag[
static_cast<std::size_t
>(
i)] =
dsum;
239 start[
static_cast<std::size_t
>(
i) + 1] =
240 start[
static_cast<std::size_t
>(
i)] +
241 static_cast<Index>(
rows[
static_cast<std::size_t
>(
i)].size());
242 const Index nnz = start[
static_cast<std::size_t
>(n)];
243 std::vector<Index> nbr(
static_cast<std::size_t
>(
nnz));
244 std::vector<double> coef(
static_cast<std::size_t
>(
nnz));
246 Index k = start[
static_cast<std::size_t
>(
i)];
248 nbr[
static_cast<std::size_t
>(k)] =
e.first;
249 coef[
static_cast<std::size_t
>(k)] =
e.second;
253 Level&
lv = levels_[
L];
256 lv.op.faceStart =
toDevice(start,
"vmg_fstart");
260 lv.col = greedyColoring(start, nbr, n);
264 void buildTransfer(std::size_t
L) {
265 const Octree&
f = hmg_->op(
L).octree();
266 const Octree&
c = hmg_->op(
L + 1).octree();
267 const Index nf =
f.numLeaves(),
nc =
c.numLeaves();
268 std::vector<Index> c2p(
static_cast<std::size_t
>(
nf));
269 std::vector<Index>
cnt(
static_cast<std::size_t
>(
nc), 0);
271 Code par = M::from_code(
f.code(
i)).ancestor(
f.level(
i) + 1).code();
273 c2p[
static_cast<std::size_t
>(
i)] =
p;
275 ++
cnt[
static_cast<std::size_t
>(
p)];
277 std::vector<Index>
cstart(
static_cast<std::size_t
>(
nc) + 1, 0);
279 cstart[
static_cast<std::size_t
>(
p) + 1] =
280 cstart[
static_cast<std::size_t
>(
p)] +
cnt[
static_cast<std::size_t
>(
p)];
281 std::vector<Index>
cidx(
static_cast<std::size_t
>(
nf));
284 Index p = c2p[
static_cast<std::size_t
>(
i)];
286 cidx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(
p)]++)] =
i;
288 levels_[
L].c2p =
toDevice(c2p,
"vmg_c2p");
293 std::unique_ptr<AmrMultigrid<3, Bits>> hmg_;
294 std::vector<Level> levels_;
Per-block adaptive octree over block-local Morton codes.
morton::Morton< Dim, Bits > M
typename M::code_type Code
View< double > x(std::size_t L=0)
void setGaussSeidel(bool on)
Opt-in: use multicolour Gauss–Seidel as the smoother (per-level colouring) instead of Jacobi — the st...
Index numLeaves(std::size_t L=0) const
void vcycle(int pre=2, int post=2, int bottom=30, double omega=0.7, std::size_t L=0)
One V-cycle (correction scheme) solving the fine operator.
void setFineOp(const MomentumOp &fineOp)
Re-point level 0 at the (possibly FOU-updated) fine operator before a solve.
AmrPoisson< 3, Bits > Poisson
BlockOctree< 3, Bits > Octree
void build(const Octree &finest, double h0, double idiag, double mu, const MomentumOp &fineOp, const std::vector< double > &kappa, const std::vector< char > &fluid, const std::vector< char > &cut, Index minCoarse=256)
Build the rediscretized hierarchy.
std::size_t numLevels() const
View< double > b(std::size_t L=0)
typename Octree::Code Code
void build(const Octree &finest, const Vec< 3 > &h0, double idiag, double mu, const MomentumOp &fineOp, const std::vector< double > &kappa, const std::vector< char > &fluid, const std::vector< char > &cut, Index minCoarse=256)
Phase 3: the finest spacing per axis; every coarse level inherits the aspect ratio (AM1).
void zeroMasked(View< double > v, View< const char > excl, Index n)
Zero v at excluded cells (excl != 0).
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...
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).
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,...