50#include <Kokkos_Core.hpp>
90 const C3 e{nx + 2 *
G,
ny + 2 *
G, nz + 2 *
G};
91 const std::size_t
n = (std::size_t)
e.x *
e.y *
e.z;
92 const double k = 2.0 *
M_PI /
L;
94 CCField ox(
"ox", n), oy(
"oy", n), oz(
"oz", n);
95 Kokkos::deep_copy(ox, 1.0);
96 Kokkos::deep_copy(oy, 1.0);
97 Kokkos::deep_copy(oz, 1.0);
100 std::vector<double>
hb(n, 0.0),
hex(n, 0.0);
101 for (
int z =
G;
z <
e.z -
G; ++
z)
102 for (
int y =
G;
y <
e.y -
G; ++
y)
103 for (
int x =
G;
x <
e.x -
G; ++
x) {
104 const double px = ((
x -
G) + 0.5) *
hx, py = ((
y -
G) + 0.5) *
hy,
105 pz = ((
z -
G) + 0.5) *
hz;
106 const double ph = std::cos(k * px) * std::cos(k * py) * std::cos(k * pz);
107 const std::size_t
i =
108 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
112 CCField b(
"b", n), xf(
"x", n),
r(
"r", n),
p(
"p", n),
zz(
"z", n),
Ap(
"Ap", n);
114 auto m = Kokkos::create_mirror_view(b);
115 for (std::size_t i = 0;
i <
n; ++
i)
117 Kokkos::deep_copy(b, m);
119 Kokkos::deep_copy(xf, 0.0);
127 mg.
init(nx, ny, nz, 6);
134 out.iters = mg.
solveFCG(b, xf, r, p,
zz, zp,
Ap, 500, 1e-10, 2, 2, 12);
136 out.iters = mg.
solvePCG(b, xf, r, p,
zz,
Ap, 500, 1e-10, 2, 2, 12);
144 const double lam =
wx * 2.0 * (1.0 - std::cos(k *
hx)) +
wy * 2.0 * (1.0 - std::cos(k *
hy)) +
145 wz * 2.0 * (1.0 - std::cos(k *
hz));
146 out.l2exact = std::fabs(3.0 * k * k *
dref *
dref / lam - 1.0) * std::pow(0.5, 1.5);
149 auto hr = Kokkos::create_mirror_view(r);
150 Kokkos::deep_copy(
hr, r);
151 double rm = 0.0,
bm = 0.0;
152 for (
int z =
G;
z <
e.z -
G; ++
z)
153 for (
int y =
G;
y <
e.y -
G; ++
y)
154 for (
int x =
G;
x <
e.x -
G; ++
x) {
155 const std::size_t
i =
156 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
157 if (!(std::fabs(
hr(i)) <=
rm))
158 rm = std::fabs(
hr(i));
159 if (!(std::fabs(hb[i]) <=
bm))
160 bm = std::fabs(hb[i]);
165 auto hxv = Kokkos::create_mirror_view(xf);
166 Kokkos::deep_copy(
hxv, xf);
169 double ma = 0.0,
mb = 0.0;
171 for (
int z =
G;
z <
e.z -
G; ++
z)
172 for (
int y =
G;
y <
e.y -
G; ++
y)
173 for (
int x =
G;
x <
e.x -
G; ++
x) {
174 const std::size_t
i =
175 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
183 for (
int z =
G;
z <
e.z -
G; ++
z)
184 for (
int y =
G;
y <
e.y -
G; ++
y)
185 for (
int x =
G;
x <
e.x -
G; ++
x) {
186 const std::size_t
i =
187 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
191 out.l2 = std::sqrt(acc / (
double)cnt);
196double fitOrder(
const std::vector<int>& Ns,
const std::vector<double>& err) {
197 const int m = (
int)
Ns.size();
198 double sx = 0, sy = 0,
sxx = 0,
sxy = 0;
199 for (
int i = 0;
i <
m; ++
i) {
200 const double X = std::log((
double)Ns[i]),
Y = std::log(err[i]);
210 const std::vector<int>
Ns{16, 32, 64};
211 std::vector<double>
err;
212 std::printf(
" %s, %s:\n",
213 stretched ?
"stretched (N, 2N, N/2), w = (1, 4, 1/4)"
214 :
"cubic control (N, N, N), w = (1, 1, 1)",
215 fcg ?
"FCG (the converged control)" :
"MG-PCG (the §8.5 driver)");
218 err.push_back(
rr.l2);
220 " N = %3d cells %4d x %4d x %4d levels %d %3d iters r/|b| %.2e "
221 "L2 err %.6e (exact discrete %.6e)",
225 std::printf(
" order %.4f", std::log(err[
err.size() - 2] /
err.back()) / std::log(2.0));
229 std::printf(
" least-squares order = %.4f (require >= %.2f)\n",
ord,
minOrder);
242std::vector<C3>
levelTable(
int nx,
int ny,
int nz,
const double hp[3],
int levels,
248 mg.
init(nx, ny, nz, levels);
252void printTable(
const char* what,
const std::vector<C3>& t) {
253 std::printf(
" %-46s", what);
254 for (
const C3& r :
t)
259bool sameTable(
const std::vector<C3>& a,
const std::vector<C3>& b) {
260 if (
a.size() !=
b.size())
262 for (std::size_t i = 0;
i <
a.size(); ++
i)
263 if (a[i].x != b[i].x || a[i].y != b[i].y || a[i].z != b[i].z)
269 std::printf(
" LEVEL TABLE (§8.5, C3), levels = 6, theta = %.4g:\n",
gTheta);
270 const double hpS[3] = {1.0, 0.5, 2.0};
271 const double hpC[3] = {1.0, 1.0, 1.0};
272 const C3 want[4] = {{1, 2, 1}, {2, 2, 1}, {2, 2, 2}, {2, 2, 2}};
273 for (
int N : {16, 32, 64}) {
278 std::printf(
" N = %3d\n",
N);
279 printTable(
"stretched (N, 2N, N/2), hp = (1, 1/2, 2)", st);
285 for (
int L = 0;
L < 4; ++
L)
286 if (!(st[(std::size_t)L].x == want[L].x && st[(std::size_t)L].y == want[L].y &&
287 st[(std::size_t)L].z == want[L].z)) {
289 "FAIL: N = %d stretched level %d ratio (%d,%d,%d), expected (%d,%d,%d)\n",
N,
290 L, st[(std::size_t)L].x, st[(std::size_t)L].y, st[(std::size_t)L].z, want[L].x,
291 want[L].y, want[L].z);
296 std::fprintf(
stderr,
"FAIL: N = %d cubic level table moved with the metric set\n",
N);
299 for (std::size_t L = 0;
L + 1 <
cu.size(); ++
L)
300 if (!(
cu[L].x == 2 &&
cu[L].y == 2 &&
cu[L].z == 2)) {
301 std::fprintf(
stderr,
"FAIL: N = %d cubic level %zu is not (2,2,2)\n",
N, L);
314 const int nx =
l0.inner.x,
ny =
l0.inner.y, nz =
l0.inner.z;
315 auto hx = Kokkos::create_mirror_view(
l0.x);
316 Kokkos::deep_copy(
hx,
l0.x);
317 auto hAC = Kokkos::create_mirror_view(
l0.AC);
319 auto hAFX = Kokkos::create_mirror_view(
l0.AFX);
320 auto hAFY = Kokkos::create_mirror_view(
l0.AFY);
321 auto hAFZ = Kokkos::create_mirror_view(
l0.AFZ);
322 Kokkos::deep_copy(
hAC,
l0.AC);
323 Kokkos::deep_copy(
hAFX,
l0.AFX);
324 Kokkos::deep_copy(
hAFY,
l0.AFY);
325 Kokkos::deep_copy(
hAFZ,
l0.AFZ);
326 const std::size_t sy =
e.x, sz = (std::size_t)
e.x *
e.y;
327 auto hAW = [&](std::size_t
c) {
return hAFX(c); };
328 auto hAE = [&](std::size_t
c) {
return hAFX(c + 1); };
329 auto hAS = [&](std::size_t
c) {
return hAFY(c); };
330 auto hAN = [&](std::size_t
c) {
return hAFY(c + sy); };
331 auto hAB = [&](std::size_t
c) {
return hAFZ(c); };
332 auto hAT = [&](std::size_t
c) {
return hAFZ(c + sz); };
333 auto id = [&](
int i,
int j,
int k) {
334 const int wi = (
i % nx + nx) % nx,
wj = (j % ny + ny) %
ny,
wk = (
k % nz + nz) % nz;
335 return (std::size_t)(
wi +
G) + (std::size_t)(
wj +
G) *
e.x +
336 (std::size_t)(
wk +
G) * (std::size_t)
e.x *
e.y;
339 for (
int k = 0;
k < nz; ++
k)
340 for (
int j = 0;
j <
ny; ++
j)
341 for (
int i = 0;
i < nx; ++
i) {
342 const std::size_t
c = id(i, j, k);
348 const double r =
b[
c] -
Ax;
349 if (!(std::fabs(r) <= m))
360 const int nx =
N,
ny = 2 *
N, nz =
N / 2;
361 const C3 e{nx + 2 *
G,
ny + 2 *
G, nz + 2 *
G};
362 const std::size_t
n = (std::size_t)
e.x *
e.y *
e.z;
363 CCField ox(
"ox", n), oy(
"oy", n), oz(
"oz", n);
364 Kokkos::deep_copy(ox, 1.0);
365 Kokkos::deep_copy(oy, 1.0);
366 Kokkos::deep_copy(oz, 1.0);
369 const double hp[3] = {1.0, 0.5, 2.0};
371 mg.
init(nx, ny, nz, 6);
376 std::vector<double>
hb(n, 0.0);
377 unsigned int st = 12345u;
380 for (
int k = 0;
k < nz; ++
k)
381 for (
int j = 0;
j <
ny; ++
j)
382 for (
int i = 0;
i < nx; ++
i) {
383 st =
st * 1103515245u + 12345u;
384 const double v = (
double)((st >> 16) & 0x7fff) / 32767.0 - 0.5;
385 hb[(std::size_t)(i +
G) + (std::size_t)(j +
G) *
e.x +
386 (std::size_t)(k +
G) * (std::size_t)
e.x *
e.y] = v;
391 for (
int k = 0;
k < nz; ++
k)
392 for (
int j = 0;
j <
ny; ++
j)
393 for (
int i = 0;
i < nx; ++
i)
394 hb[(std::size_t)(
i +
G) + (std::size_t)(
j +
G) *
e.x +
395 (std::size_t)(
k +
G) * (std::size_t)
e.x *
e.y] -=
mean;
399 auto m = Kokkos::create_mirror_view(
l0.rhs);
400 for (std::size_t i = 0;
i <
n; ++
i)
402 Kokkos::deep_copy(
l0.rhs, m);
404 Kokkos::deep_copy(
l0.x, 0.0);
406 " V-CYCLE RATE (§8.5 rate (a)), stretched (%d, %d, %d), 2/2 sweeps, random "
410 for (
int c = 1;
c <= 8; ++
c) {
413 const double f = (
c > 1 &&
prev > 0.0) ?
rn / prev : 0.0;
415 std::printf(
" cycle %d max|r| %.6e factor %.4f\n", c,
rn, f);
419 std::printf(
" cycle %d max|r| %.6e\n", c,
rn);
423 std::printf(
" worst reduction factor over cycles 2-8 = %.4f (require <= %.2f)\n", worst,
426 std::fprintf(
stderr,
"FAIL: V-cycle reduction factor %.4f > %.2f\n", worst,
maxFactor);
436 const double L = 1.0;
437 const double hx =
L / nx,
hy =
L /
ny,
hz =
L / nz;
440 const double wx = 1.0 / (hp[0] * hp[0]),
wy = 1.0 / (hp[1] * hp[1]),
wz = 1.0 / (hp[2] * hp[2]);
441 const C3 e{nx + 2 *
G,
ny + 2 *
G, nz + 2 *
G};
442 const std::size_t
n = (std::size_t)
e.x *
e.y *
e.z;
443 const double R = 0.3722 *
L;
445 CCField sdf(
"sdf", n),
ox(
"ox", n), oy(
"oy", n), oz(
"oz", n);
447 auto m = Kokkos::create_mirror_view(sdf);
448 for (
int k = 0;
k <
e.z; ++
k)
449 for (
int j = 0;
j <
e.y; ++
j)
450 for (
int i = 0;
i <
e.x; ++
i) {
451 double px = ((
i -
G) + 0.5) *
hx - 0.5 *
L, py = ((
j -
G) + 0.5) *
hy - 0.5 *
L,
452 pz = ((
k -
G) + 0.5) *
hz - 0.5 *
L;
453 px -=
L * std::round(px / L);
454 py -=
L * std::round(py / L);
455 pz -=
L * std::round(pz / L);
456 const double d = std::sqrt(px * px + py * py + pz * pz) -
R;
457 m((std::size_t)i + (std::size_t)j *
e.x + (std::size_t)k * (std::size_t)
e.x *
e.y) =
460 Kokkos::deep_copy(sdf, m);
467 mg.
init(nx, ny, nz, 6);
472 std::vector<double>
hb(n, 0.0);
474 auto hAC = Kokkos::create_mirror_view(mg.
level(0).
AC);
476 const double k = 2.0 *
M_PI /
L;
479 for (
int z =
G;
z <
e.z -
G; ++
z)
480 for (
int y =
G;
y <
e.y -
G; ++
y)
481 for (
int x =
G;
x <
e.x -
G; ++
x) {
482 const std::size_t
i =
483 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
484 if (!(
hAC(i) > 0.0f))
486 const double px = ((
x -
G) + 0.5) *
hx, py = ((
y -
G) + 0.5) *
hy,
487 pz = ((
z -
G) + 0.5) *
hz;
488 const double v = std::cos(k * px) * std::cos(k * py) * std::cos(k * pz);
493 const double mean = cnt ? sum / (
double)cnt : 0.0;
494 for (
int z =
G;
z <
e.z -
G; ++
z)
495 for (
int y =
G;
y <
e.y -
G; ++
y)
496 for (
int x =
G;
x <
e.x -
G; ++
x) {
497 const std::size_t
i =
498 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
503 CCField b(
"b", n), xf(
"x", n),
r(
"r", n),
pp(
"p", n),
zz(
"z", n),
Ap(
"Ap", n);
505 auto m = Kokkos::create_mirror_view(b);
506 for (std::size_t i = 0;
i <
n; ++
i)
508 Kokkos::deep_copy(b, m);
510 Kokkos::deep_copy(xf, 0.0);
515 out.iters = mg.
solveFCG(b, xf, r,
pp,
zz, zp,
Ap, 500, 1e-10, 2, 2, 12);
517 out.iters = mg.
solvePCG(b, xf, r,
pp,
zz,
Ap, 500, 1e-10, 2, 2, 12);
520 auto hr = Kokkos::create_mirror_view(r);
521 Kokkos::deep_copy(
hr, r);
522 double rm = 0.0,
bm = 0.0;
523 for (
int z =
G;
z <
e.z -
G; ++
z)
524 for (
int y =
G;
y <
e.y -
G; ++
y)
525 for (
int x =
G;
x <
e.x -
G; ++
x) {
526 const std::size_t
i =
527 (std::size_t)x + (std::size_t)
y *
e.x + (std::size_t)z * (std::size_t)
e.x *
e.y;
528 if (!(std::fabs(
hr(i)) <=
rm))
529 rm = std::fabs(
hr(i));
530 if (!(std::fabs(hb[i]) <=
bm))
531 bm = std::fabs(hb[i]);
540 " SPHERE RATE (§8.5 rate (b)/(c)), Zick & Homsy phi = 0.216, MG-PCG rtol 1e-10, "
543 for (
int N : {32, 64}) {
548 " N = %3d stretched %4d x %4d x %4d levels %d PCG %3d iters (r/|b| %.2e)"
550 N,
N, 2 *
N,
N / 2,
st.levels,
st.iters,
st.rrel,
stF.iters);
552 " cubic %4d x %4d x %4d levels %d PCG %3d iters (r/|b| %.2e)"
553 " [require stretched <= cubic + 2 = %d]\n",
554 N,
N,
N,
cu.levels,
cu.iters,
cu.rrel,
cu.iters + 2);
556 std::fprintf(
stderr,
"FAIL: N = %d stretched PCG %d iters > cubic %d + 2\n",
N,
st.iters,
565 for (
int i = 1; i <
argc; ++i)
566 if (std::strncmp(argv[i],
"--theta=", 8) == 0)
567 gTheta = std::atof(argv[i] + 8);
568 Kokkos::initialize(
argc, argv);
570 std::printf(
"=== cutcellmg_aniso (G4-order, doc/anisotropic_metric.md §8.5) ===\n");
571 ladder(
true,
false, 1.95);
572 ladder(
false,
false, 1.95);
581 ladder(
false,
true, 1.95);
582 std::printf(
"=== C3 — the aspect-ratio coarsening rule (doc/anisotropic_metric.md §5) ===\n");
585 " --theta=%.4g -> ABLATION RUN: the gates below PRINT, they do "
586 "not assert (§8.5 item (c)).\n",
int solvePCG(CCField b, CCField x, CCField r, CCField p, CCField z, CCField Ap, int maxit, double rtol, int pre, int post, int bottom, const StarOverlay *star=nullptr, int nStar=0, C3 nnStar=C3{0, 0, 0})
void setMetric(const double hp[3])
Per-axis cell spacings h_a' = h_a / hRef of the physical domain (doc/anisotropic_metric....
std::vector< C3 > levelRatios() const
The per-level coarsening ratio actually chosen (the level table of §5, gate §8.5).
void vcycle(int L, bool sym)
void setOpenness(CCConst ox, CCConst oy, CCConst oz, double idx2, double idy2, double idz2)
void setAspectThreshold(double theta)
Anisotropic-coarsening aspect threshold theta (see aspectTheta_).
void init(int nx, int ny, int nz, int nLevels)
int solveFCG(CCField b, CCField x, CCField r, CCField p, CCField z, CCField zp, CCField Ap, int maxit, double rtol, int pre, int post, int bottom, const StarOverlay *star=nullptr, int nStar=0, C3 nnStar=C3{0, 0, 0})
flow — portable (Kokkos) cut-cell pressure-operator face openness from an SDF.
flow — portable (Kokkos) geometric multigrid for the cut-cell (variable-openness) pressure Poisson.
Kokkos::View< double *, CCMem > CCField
void buildOpenness(CCField ox, CCField oy, CCField oz, CCConst sdf, C3 ext, double dx, double dy, double dz, int order=1)
Kokkos::View< const double *, CCMem > CCConst
static double mean(const std::vector< double > &a)