9#ifndef PECLET_FLOW_MAC_MG_HPP
10#define PECLET_FLOW_MAC_MG_HPP
12#include <Kokkos_Core.hpp>
23 int dims[3] = {e.x, e.y, e.z};
24 long st[3] = {1, e.x, (long)e.x * e.y};
25 for (
int axis = 0; axis < 3; ++axis) {
26 const int b = (axis + 1) % 3, c = (axis + 2) % 3;
27 const long sa = st[axis], sb = st[b], sc = st[c];
29 using MD = Kokkos::MDRangePolicy<SExec, Kokkos::Rank<2>>;
31 "peclet::flow::mg_pfill", MD(space, {0, 0}, {dims[b], dims[c]}),
32 KOKKOS_LAMBDA(
int p0,
int p1) {
33 const long base = (long)p0 * sb + (
long)p1 * sc;
34 for (
int gl = 0; gl < g; ++gl) {
35 ff(base + (
long)gl * sa) = ff(base + (
long)(gl +
N) * sa);
36 ff(base + (
long)(g +
N + gl) * sa) = ff(base + (
long)(g + gl) * sa);
52 L.
e =
I3{n + 2 *
G, n + 2 *
G, n + 2 *
G};
53 const std::size_t ne = (std::size_t)L.
e.
x * L.
e.
y * L.
e.
z;
58 if (n % 2 != 0 || n / 2 < minN)
73 "peclet::flow::mg_negd", Kokkos::RangePolicy<SExec>(space, 0, f0.extent(0)),
74 KOKKOS_LAMBDA(std::size_t i) { f0(i) = -d(i); });
76 Kokkos::deep_copy(
lv_[0].phi, phi);
77 for (
int v = 0; v < nVcycles; ++v) {
81 Kokkos::deep_copy(phi,
lv_[0].phi);
92 static constexpr int G = 1;
99 std::vector<Level>
lv_;
105 const double h2 = L.
h2;
107 using MD = Kokkos::MDRangePolicy<SExec, Kokkos::Rank<3>>;
108 Kokkos::parallel_for(
109 "peclet::flow::mg_smooth", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
110 KOKKOS_LAMBDA(
int x,
int y,
int z) {
111 if (((x + y + z) & 1) != color)
113 const long i =
L3(x, y, z, e), sx = 1, sy = e.x, sz = (long)e.x * e.y;
115 phi(i + sx) + phi(i - sx) + phi(i + sy) + phi(i - sy) + phi(i + sz) + phi(i - sz);
116 phi(i) = (s + h2 * f(i)) / 6.0;
120 for (
int it = 0; it < sweeps; ++it) {
132 const double h2 = L.
h2;
134 using MD = Kokkos::MDRangePolicy<SExec, Kokkos::Rank<3>>;
135 Kokkos::parallel_for(
136 "peclet::flow::mg_resid", MD(space, {
G,
G,
G}, {e.x -
G, e.y -
G, e.z -
G}),
137 KOKKOS_LAMBDA(
int x,
int y,
int z) {
138 const long i =
L3(x, y, z, e), sx = 1, sy = e.x, sz = (long)e.x * e.y;
140 phi(i + sx) + phi(i - sx) + phi(i + sy) + phi(i - sy) + phi(i + sz) + phi(i - sz);
141 r(i) = f(i) - (6.0 * phi(i) - s) / h2;
146 if (l == (
int)
lv_.size() - 1) {
154 Kokkos::deep_copy(C.
phi, 0.0);
156 T3{C.N, C.N, C.N},
T3{2, 2, 2});
161 T3{L.N, L.N, L.N},
T3{2, 2, 2});
169 Kokkos::parallel_reduce(
170 "peclet::flow::mg_mean", Kokkos::RangePolicy<SExec>(space, 0, (
long)
N *
N *
N),
171 KOKKOS_LAMBDA(
long c,
double& acc) {
172 const int ix = (int)(c %
N), iy = (int)((c /
N) %
N), iz = (
int)(c / ((long)
N *
N));
173 acc += f(
L3(ix +
G, iy +
G, iz +
G, e));
176 const double mean = sum / ((double)
N *
N *
N);
177 Kokkos::parallel_for(
178 "peclet::flow::mg_submean", Kokkos::RangePolicy<SExec>(space, 0, f.extent(0)),
179 KOKKOS_LAMBDA(std::size_t i) { f(i) -= mean; });
186 Kokkos::parallel_reduce(
187 "peclet::flow::mg_maxabs", Kokkos::RangePolicy<SExec>(space, 0, (
long)
N *
N *
N),
188 KOKKOS_LAMBDA(
long c,
double& acc) {
189 const int ix = (int)(c %
N), iy = (int)((c /
N) %
N), iz = (
int)(c / ((long)
N *
N));
190 double v = Kokkos::fabs(f(
L3(ix +
G, iy +
G, iz +
G, e)));
194 Kokkos::Max<double>(m));
double finestResidualMax()
double maxAbsInner(SField f, Level &L)
MgPoisson(int N, int minN=4)
void smoothColor(Level &L, int color)
void vcycle(int l, int nu1, int nu2)
void removeMean(SField f, Level &L)
void computeResidual(int l)
void smooth(Level &L, int sweeps)
void solve(SField phi, SConst d, int nVcycles, int nu1=2, int nu2=2)
flow — portable (Kokkos) MAC stencil operators: Red-Black Gauss-Seidel smoothers + divergence.
flow — portable (Kokkos) multigrid transfer operators + projection velocity correction.
long L3(int x, int y, int z, I3 e)
void restrict_(TField coarse, TConst fine, T3 cext, T3 fext, int g, T3 cinner, T3 ratio)
void prolong(TField fine, TConst coarse, T3 fext, T3 cext, int g, T3 finner, T3 ratio)
Kokkos::View< const double *, SMem > SConst
void mgPeriodicFill(SField f, I3 e, int N, int g)
Kokkos::DefaultExecutionSpace SExec
Kokkos::View< double *, SMem > SField