16#ifndef PECLET_CORE_SOLVER_GRAPH_AMG_DEVICE_HPP
17#define PECLET_CORE_SOLVER_GRAPH_AMG_DEVICE_HPP
19#include <Kokkos_Core.hpp>
44 Kokkos::deep_copy(
l0.b, r);
45 Kokkos::deep_copy(
l0.x, 0.0);
47 Kokkos::deep_copy(z,
l0.x);
69 View<T> d(Kokkos::view_alloc(std::string(
name), Kokkos::WithoutInitializing), v.size());
70 auto h = Kokkos::create_mirror_view(
d);
71 for (std::size_t
i = 0;
i < v.size(); ++
i)
73 Kokkos::deep_copy(
d, h);
79 for (
const auto&
hl : host_.
levels()) {
84 d.start =
toDev(
hl.A.start,
"amgd_start");
86 d.coef =
toDev(
hl.A.coef,
"amgd_coef");
87 d.diag =
toDev(
hl.A.diag,
"amgd_diag");
88 d.invDiag =
toDev(
hl.invDiag,
"amgd_invDiag");
89 if (!
hl.Pstart.empty()) {
90 d.Pstart =
toDev(
hl.Pstart,
"amgd_Pstart");
91 d.Pcol =
toDev(
hl.Pcol,
"amgd_Pcol");
92 d.Pval =
toDev(
hl.Pval,
"amgd_Pval");
96 std::vector<Index> Rstart((std::size_t)
hl.nc + 1, 0), Rcol(
hl.Pcol.size());
97 std::vector<double> Rval(
hl.Pval.size());
99 ++Rstart[(std::size_t)c + 1];
100 for (std::size_t c = 0; c < (std::size_t)
hl.nc; ++c)
101 Rstart[c + 1] += Rstart[c];
102 std::vector<Index>
cur(Rstart.begin(), Rstart.end() - 1);
104 for (
Index k =
hl.Pstart[(std::size_t)
i];
k <
hl.Pstart[(std::size_t)
i + 1]; ++
k) {
105 const Index c =
hl.Pcol[(std::size_t)
k];
106 const Index at =
cur[(std::size_t)c]++;
107 Rcol[(std::size_t)at] =
i;
108 Rval[(std::size_t)at] =
hl.Pval[(std::size_t)
k];
110 d.Rstart =
toDev(Rstart,
"amgd_Rstart");
111 d.Rcol =
toDev(Rcol,
"amgd_Rcol");
112 d.Rval =
toDev(Rval,
"amgd_Rval");
114 auto scratch = [n = (std::size_t)
d.n](
const char*
nm) {
115 return DView(Kokkos::view_alloc(std::string(
nm), Kokkos::WithoutInitializing), n);
122 lv_.push_back(std::move(
d));
133 Kokkos::parallel_for(
134 "peclet::core::amgd_spmv", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
136 double s = diag(
i) * x(
i);
137 for (
Index k = start(
i);
k < start(
i + 1); ++
k)
138 s += coef(
k) * x(nbr(
k));
145 if (
L + 1 == (
int)lv_.size()) {
153 Kokkos::parallel_for(
154 "peclet::core::amgd_resid", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
157 const DLevel&
cl = lv_[(std::size_t)
L + 1];
159 IView Rstart =
lv.Rstart, Rcol =
lv.Rcol;
161 Kokkos::parallel_for(
162 "peclet::core::amgd_restrict", Kokkos::RangePolicy<ExecSpace>(0,
cl.n),
165 for (
Index k = Rstart(c);
k < Rstart(c + 1); ++
k)
166 s += Rval(
k) * res(Rcol(
k));
170 Kokkos::deep_copy(
cl.x, 0.0);
173 IView Pstart =
lv.Pstart, Pcol =
lv.Pcol;
175 Kokkos::parallel_for(
176 "peclet::core::amgd_prolong", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
179 for (
Index k = Pstart(
i);
k < Pstart(
i + 1); ++
k)
180 s += Pval(
k) * cx(Pcol(
k));
190 for (
int s = 0; s <
sweeps; ++s)
201 Kokkos::parallel_for(
202 "peclet::core::amgd_jacobi", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
208 const double lam = 1.1 *
lv.lmax;
211 Kokkos::parallel_for(
212 "peclet::core::amgd_cheb_r0", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
214 Kokkos::deep_copy(
d, 0.0);
215 for (
int i = 1;
i <=
k; ++
i) {
216 const double c1 = (2.0 *
i - 3.0) / (2.0 *
i + 1.0);
217 const double c2 = (8.0 *
i - 4.0) / ((2.0 *
i + 1.0) * lam);
218 Kokkos::parallel_for(
219 "peclet::core::amgd_cheb_d", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
226 Kokkos::parallel_for(
227 "peclet::core::amgd_cheb_rup", Kokkos::RangePolicy<ExecSpace>(0,
lv.n),
235 Kokkos::parallel_reduce(
236 "peclet::core::amgd_dot", Kokkos::RangePolicy<ExecSpace>(0, n),
251 Kokkos::parallel_for(
252 "peclet::core::amgd_cg_r0", Kokkos::RangePolicy<ExecSpace>(0, n),
257 double rr =
dot(r, r, n);
258 const double rr0 =
rr;
259 const int maxit = (
int)std::min<Index>(n, 200);
266 Kokkos::parallel_for(
267 "peclet::core::amgd_cg_up", Kokkos::RangePolicy<ExecSpace>(0, n),
272 const double rrn =
dot(r, r, n);
274 Kokkos::parallel_for(
275 "peclet::core::amgd_cg_p", Kokkos::RangePolicy<ExecSpace>(0, n),
284 std::vector<DLevel> lv_;
void jacobiSweep(const DLevel &lv) const
const GraphAMG & hostHierarchy() const
static View< T > toDev(const std::vector< T > &v, const char *name)
void coarseSolve(const DLevel &lv) const
void build(const HostCsrOp &A, const AmgParams &prm={})
Host setup + one-time device mirror. Rebuild whenever the operator changes.
static void spmv(const DLevel &lv, const DView &x, const DView &y)
static double dot(const DView &a, const DView &b, Index n)
Index size(int L=0) const
void smooth(const DLevel &lv, int sweeps) const
void apply(const DView &r, const DView &z) const
z = M⁻¹ r: one V-cycle (correction scheme) from a zero initial guess. Device views,...
void chebSweep(const DLevel &lv) const
Smoothed-aggregation AMG hierarchy usable as z = M⁻¹ r (one symmetric V-cycle from a zero initial gue...
void build(const HostCsrOp &A, const AmgParams &prm={})
const std::vector< Level > & levels() const
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).
int coarseSweeps
coarsest level: 0 ⇒ a near-exact CG solve; >0 ⇒ this many smoother sweeps instead (with maxLevels=1 t...
double jacobiOmega
damped-Jacobi smoother relaxation (used when chebDegree == 0)
int chebDegree
Chebyshev smoother polynomial degree; 0 ⇒ damped-Jacobi smoother.
int post
smoother sweeps per level (pre == post keeps the V-cycle symmetric)
A general assembled sparse operator in CSR form: the diagonal is stored separately and the CSR (start...