21#ifndef PECLET_CORE_AMR_MOMENTUM_HPP
22#define PECLET_CORE_AMR_MOMENTUM_HPP
24#ifdef PECLET_CORE_HAVE_MORTON
88 "amr::mom_residual", op.
n,
101 tmp(
i) = (d != 0.0) ? (b(
i) - off) / d :
u(
i);
103 Kokkos::parallel_for(
104 "amr::mom_jacobi_update", op.
n,
111 Kokkos::parallel_reduce(
120 Kokkos::parallel_for(
121 "amr::mom_pupdate", n,
158 std::vector<Index>
deg(
static_cast<std::size_t
>(n) + 1, 0);
162 ++
deg[
static_cast<std::size_t
>(
i) + 1];
163 ++
deg[
static_cast<std::size_t
>(nbr[
static_cast<std::size_t
>(k)]) + 1];
166 deg[
static_cast<std::size_t
>(
i) + 1] +=
deg[
static_cast<std::size_t
>(
i)];
168 std::vector<Index>
aNbr(
static_cast<std::size_t
>(
deg[
static_cast<std::size_t
>(n)]));
169 std::vector<Index>
acur(
deg.begin(),
deg.end() - 1);
173 const Index j = nbr[
static_cast<std::size_t
>(k)];
174 aNbr[
static_cast<std::size_t
>(
acur[
static_cast<std::size_t
>(
i)]++)] =
j;
175 aNbr[
static_cast<std::size_t
>(
acur[
static_cast<std::size_t
>(
j)]++)] =
i;
177 std::vector<int>
color(
static_cast<std::size_t
>(n), -1);
178 std::vector<int>
stamp;
183 const int nc =
color[
static_cast<std::size_t
>(
aNbr[
static_cast<std::size_t
>(k)])];
185 if (
static_cast<std::size_t
>(nc) >=
stamp.size())
186 stamp.resize(
static_cast<std::size_t
>(nc) + 1, -1);
187 stamp[
static_cast<std::size_t
>(nc)] =
static_cast<int>(
i);
191 while (
c <
static_cast<int>(
stamp.size()) &&
192 stamp[
static_cast<std::size_t
>(
c)] ==
static_cast<int>(
i))
194 color[
static_cast<std::size_t
>(
i)] =
c;
200 col.
hStart.assign(
static_cast<std::size_t
>(nColors) + 1, 0);
202 ++col.
hStart[
static_cast<std::size_t
>(
color[
static_cast<std::size_t
>(
i)]) + 1];
203 for (
int c = 0;
c < nColors; ++
c)
204 col.
hStart[
static_cast<std::size_t
>(
c) + 1] += col.
hStart[
static_cast<std::size_t
>(
c)];
205 std::vector<Index> idx(
static_cast<std::size_t
>(n));
208 const int c =
color[
static_cast<std::size_t
>(
i)];
209 idx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(
c)]++)] =
i;
232 Kokkos::parallel_for(
261template <
unsigned Bits = 21u>
271 const std::vector<Index>&
start0,
const std::vector<Index>&
nbr0,
272 const std::vector<double>&
coef0) {
278 if (
merged == 0 ||
c.numLeaves() == octs_.back().numLeaves())
281 if (
c.numLeaves() == 1)
284 const std::size_t
nl = octs_.size();
292 for (std::size_t
L = 0;
L + 1 <
nl; ++
L) {
295 const Index nf =
f.numLeaves(), nc =
c.numLeaves();
296 std::vector<Index> c2p(
static_cast<std::size_t
>(
nf));
297 std::vector<Index>
cnt(
static_cast<std::size_t
>(nc), 0);
299 Code par = M::from_code(
f.code(
i)).ancestor(
f.level(
i) + 1).code();
301 c2p[
static_cast<std::size_t
>(
i)] = p;
303 ++
cnt[
static_cast<std::size_t
>(p)];
305 std::vector<Index>
cstart(
static_cast<std::size_t
>(nc) + 1, 0);
306 for (
Index p = 0; p < nc; ++p)
307 cstart[
static_cast<std::size_t
>(p) + 1] =
308 cstart[
static_cast<std::size_t
>(p)] +
cnt[
static_cast<std::size_t
>(p)];
309 std::vector<Index>
cidx(
static_cast<std::size_t
>(
nf));
312 Index p = c2p[
static_cast<std::size_t
>(
i)];
314 cidx[
static_cast<std::size_t
>(
cur[
static_cast<std::size_t
>(p)]++)] =
i;
316 levels_[
L].c2p =
toDevice(c2p,
"mmg_c2p");
321 std::vector<std::map<Index, double>>
acc(
static_cast<std::size_t
>(nc));
323 Index p = c2p[
static_cast<std::size_t
>(
i)];
326 const double w = 1.0 /
static_cast<double>(
cnt[
static_cast<std::size_t
>(p)]);
327 acc[
static_cast<std::size_t
>(p)][p] +=
w *
hdiag[
static_cast<std::size_t
>(
i)];
330 Index q = c2p[
static_cast<std::size_t
>(
hnbr[
static_cast<std::size_t
>(k)])];
333 acc[
static_cast<std::size_t
>(p)][
q] +=
w *
hcoef[
static_cast<std::size_t
>(k)];
336 std::vector<double>
cdiag(
static_cast<std::size_t
>(nc), 0.0);
337 std::vector<Index>
cs(
static_cast<std::size_t
>(nc) + 1, 0);
338 for (
Index p = 0; p < nc; ++p) {
340 for (
auto&
e :
acc[
static_cast<std::size_t
>(p)]) {
342 cdiag[
static_cast<std::size_t
>(p)] =
e.second;
346 cs[
static_cast<std::size_t
>(p) + 1] =
cs[
static_cast<std::size_t
>(p)] + off;
348 std::vector<Index>
cn(
static_cast<std::size_t
>(
cs[
static_cast<std::size_t
>(nc)]));
349 std::vector<double>
ccoef(
static_cast<std::size_t
>(
cs[
static_cast<std::size_t
>(nc)]));
350 for (
Index p = 0; p < nc; ++p) {
351 Index k =
cs[
static_cast<std::size_t
>(p)];
352 for (
auto&
e :
acc[
static_cast<std::size_t
>(p)])
354 cn[
static_cast<std::size_t
>(k)] =
e.first;
355 ccoef[
static_cast<std::size_t
>(k)] =
e.second;
365 for (
auto&
lv : levels_) {
379 Level&
lv = levels_[
L];
381 if (
L + 1 == levels_.size()) {
387 Level&
cl = levels_[
L + 1];
389 Kokkos::deep_copy(
cl.x, 0.0);
395 std::size_t
numLevels()
const {
return levels_.size(); }
420 void uploadLevel(std::size_t
L,
const std::vector<double>& diag,
const std::vector<Index>& start,
421 const std::vector<Index>& nbr,
const std::vector<double>& coef) {
422 Level&
lv = levels_[
L];
423 lv.op.n =
static_cast<Index>(diag.size());
425 lv.op.faceStart =
toDevice(start,
"mmg_start");
430 std::vector<Octree> octs_;
431 std::vector<Level> levels_;
441template <
unsigned Bits = 21u>
456 precFn_ = std::move(
fn);
494 applyPrec(op, r_, phat_);
517 Kokkos::deep_copy(rhat_, r_);
521 double rho = 1, alpha = 1,
omega = 1;
522 Kokkos::deep_copy(v_, 0.0);
523 Kokkos::deep_copy(p_, 0.0);
533 applyPrec(op, p_, phat_);
538 Kokkos::deep_copy(s_, r_);
547 applyPrec(op, s_, shat_);
555 Kokkos::deep_copy(r_, s_);
579 Kokkos::deep_copy(
z, 0.0);
581 Kokkos::deep_copy(
z,
v);
584 for (
int s = 0;
s < jacPre_; ++
s)
587 void ensure(
Index n) {
588 if (r_.extent(0) ==
static_cast<std::size_t
>(n))
590 auto mk = [&](
const char*
l) {
return View<double>(
l,
static_cast<std::size_t
>(n)); };
592 rhat_ =
mk(
"mom_rhat");
594 phat_ =
mk(
"mom_phat");
597 shat_ =
mk(
"mom_shat");
599 tmp_ =
mk(
"mom_tmp");
602 View<double> r_, rhat_, p_, phat_, v_, s_, shat_, t_, tmp_;
morton::Morton< Dim, Bits > M
typename M::code_type Code
Index numLeaves(std::size_t L=0) const
BlockOctree< 3, Bits > Octree
void setGaussSeidel(bool on)
Opt-in: use multicolour Gauss–Seidel as the smoother (per-level colouring built at build) instead of ...
void vcycle(int pre=2, int post=2, int bottom=30, double omega=0.7, std::size_t L=0)
One V-cycle on level L solving A u = b (correction scheme).
View< double > x(std::size_t L=0)
std::size_t numLevels() const
const MomentumOp & op(std::size_t L=0) const
View< double > b(std::size_t L=0)
typename Octree::Code Code
void build(const Octree &finest, const std::vector< double > &diag0, const std::vector< Index > &start0, const std::vector< Index > &nbr0, const std::vector< double > &coef0)
Build the Galerkin hierarchy from the finest octree + the assembled fine operator CSR (diag + face CS...
double solveJacobi(const MomentumOp &op, View< double > u, View< const double > b, int sweeps)
Plain weighted-Jacobi solve (the simple parallel mirror of the host GS smoother): sweeps damped-Jacob...
Result solveBiCGStab(const MomentumOp &op, View< double > u, View< const double > b, int maxIters=500, double tol=1e-10)
Jacobi-preconditioned BiCGStab solve of A u = b in place.
void setPreconditioner(std::function< void(View< const double >, View< double >)> fn)
Set a generic preconditioner z = M⁻¹ r (a host callable that launches device kernels) — the multigrid...
void setJacobi(int preSweeps, double omega)
Result solveDefectCorrection(const MomentumOp &op, View< double > u, View< const double > b, int maxIters=200, double tol=1e-8)
MG-preconditioned defect-correction (Richardson) solve of A u = b in place: u ← u + M⁻¹(b − A u),...
void axpy(View< double > y, double a, View< const double > x, Index n)
y += a·x
void residualMom(const MomentumOp &op, View< const double > u, View< const double > b, View< double > res)
res = b − A u.
void multicolorGSMom(const MomentumOp &op, View< double > u, View< const double > b, const Coloring &col, double omega)
One symmetric multicolour Gauss–Seidel sweep of A u = b in place (momentum operator: diag + face CSR ...
void bicgPUpdate(View< double > p, View< const double > r, View< const double > v, double beta, double omega, Index n)
BiCGStab direction update: p = r + β(p − ω v).
void prolongAdd(View< const Index > c2p, View< const double > coarse, View< double > fine, Index nFine)
Prolong (piecewise-constant) + correct: fine(i) += coarse(c2p(i)).
Coloring greedyColoring(const std::vector< Index > &start, const std::vector< Index > &nbr, Index n)
Greedy colouring of the face CSR (start/nbr, host): each cell gets the smallest colour not used by an...
MORTON_HD void faceCsrOffDiag(const Op &op, Index i, const U &u, double &off, double &d)
Off-diagonal sum and the (advection-inclusive) diagonal for the point smoothers: out off = Σ coef·u[n...
void jacobiMom(const MomentumOp &op, View< double > u, View< const double > b, View< double > tmp, double omega)
One weighted-Jacobi sweep of A u = b (in place).
MORTON_HD double faceCsrPointUpdate(double b_i, double off, double d, double uOld, double omega)
The damped point update used by both Jacobi and (multicolour) Gauss–Seidel: returns the new u_i given...
void applyMom(const MomentumOp &op, View< const double > u, View< double > Au)
Au = A u (cut-cell operator + optional implicit-FOU advection).
MORTON_HD double faceCsrApplyRow(const Op &op, Index i, const U &u)
(A u)_i — one assembled-operator row.
double dotPlain(View< const double > a, View< const double > b, Index n)
Plain (unweighted) dot product.
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).
FaceCsrOpT< View< const double >, View< const Index > > momView(const MomentumOp &op)
View the assembled momentum operator through the shared, backend-agnostic FaceCsrOpT,...
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.
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
A graph colouring of a face CSR: cells grouped by colour.
std::vector< Index > hStart
Assembled momentum operator on the device: (A u)_i = diag_i u_i + Σ coef·u[nbr], with an optional imp...
View< double > diag
size n
View< Index > advStart
face-geom CSR row offsets, size n+1
View< Index > faceNbr
neighbour leaf per off-diagonal, size nnz
View< Index > advNbr
face-geom neighbour per face, size nFaces
View< double > advDiag
per-cell outflow (diagonal) advection weight, size n
View< double > faceCoef
off-diagonal coefficient, size nnz
View< Index > faceStart
CSR row offsets, size n+1.
View< double > advCoef
per-face inflow advection coefficient (0 on outflow/solid faces)