flow 1.3.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
test_pcg_breakdown.cpp
Go to the documentation of this file.
1
22#include <cmath>
23#include <cstdio>
24#include <cstring>
25#include <Kokkos_Core.hpp>
26#include <limits>
27#include <vector>
28
29#include "mac_cutcell_mg.hpp"
30
31using namespace peclet::flow;
32
33namespace {
34
35struct Problem {
36 int n = 16;
37 C3 e{18, 18, 18};
38 std::size_t cells = 18 * 18 * 18;
39 CCField ox, oy, oz, b;
40};
41
42Problem makeProblem() {
43 Problem P;
44 const int G = CutcellMG::G, n = P.n;
45 const C3 e = P.e;
46 std::vector<double> hx(P.cells, 0.0), hy(P.cells, 0.0), hz(P.cells, 0.0), hb(P.cells, 0.0);
47 const double k = 2.0 * M_PI / n;
48 double sum = 0.0;
49 for (int z = 0; z < e.z; ++z)
50 for (int y = 0; y < e.y; ++y)
51 for (int x = 0; x < e.x; ++x) {
52 const std::size_t i =
53 (std::size_t)x + (std::size_t)y * e.x + (std::size_t)z * (std::size_t)e.x * e.y;
54 hx[i] = 1.0 + 0.5 * std::sin(k * x) * std::cos(k * z);
55 hy[i] = 1.0 + 0.5 * std::cos(k * y + 0.3);
56 hz[i] = 1.0 + 0.5 * std::sin(k * (x + z));
57 if (x >= G && x < e.x - G && y >= G && y < e.y - G && z >= G && z < e.z - G) {
58 hb[i] = std::sin(k * x) + 0.3 * std::cos(2 * k * y) * std::sin(k * z) + 0.01 * (x - y);
59 sum += hb[i];
60 }
61 }
62 const double mean = sum / ((double)n * n * n);
63 for (int z = G; z < e.z - G; ++z)
64 for (int y = G; y < e.y - G; ++y)
65 for (int x = G; x < e.x - G; ++x)
66 hb[(std::size_t)x + (std::size_t)y * e.x + (std::size_t)z * (std::size_t)e.x * e.y] -= mean;
67 auto up = [&](const std::vector<double>& h, const char* name) {
68 CCField v(name, P.cells);
69 auto m = Kokkos::create_mirror_view(v);
70 for (std::size_t i = 0; i < P.cells; ++i)
71 m(i) = h[i];
72 Kokkos::deep_copy(v, m);
73 return v;
74 };
75 P.ox = up(hx, "ox");
76 P.oy = up(hy, "oy");
77 P.oz = up(hz, "oz");
78 P.b = up(hb, "b");
79 return P;
80}
81
82struct Result {
83 int it = -1;
84 bool failed = false;
85 std::vector<double> x;
86};
87
88Result solve(const Problem& P, int maxit, int which, int iter) {
89 CutcellMG mg;
90 mg.init(P.n, P.n, P.n, 3);
91 mg.setOpenness(CCConst(P.ox), CCConst(P.oy), CCConst(P.oz), 1.0, 1.0, 1.0);
92 mg.setDebugBreakdown(which, iter);
93 CCField x("x", P.cells), r("r", P.cells), p("p", P.cells), z("z", P.cells), Ap("Ap", P.cells);
94 Result out;
95 out.it = mg.solvePCG(P.b, x, r, p, z, Ap, maxit, 1e-30, 2, 2, 12);
96 out.failed = mg.lastSolveFailed();
97 auto h = Kokkos::create_mirror_view(x);
98 Kokkos::deep_copy(h, x);
99 out.x.assign(h.data(), h.data() + P.cells);
100 return out;
101}
102
103bool sameBits(const std::vector<double>& a, const std::vector<double>& b) {
104 return a.size() == b.size() && std::memcmp(a.data(), b.data(), a.size() * sizeof(double)) == 0;
105}
106
107int check(const char* what, const Result& got, int wantIt, bool wantFailed, const Result& ref) {
108 const bool ok = got.it == wantIt && got.failed == wantFailed && sameBits(got.x, ref.x);
109 std::printf(" %-44s it %d (want %d) failed %d (want %d) x %s -> %s\n", what, got.it, wantIt,
110 (int)got.failed, (int)wantFailed, sameBits(got.x, ref.x) ? "bitwise" : "DIFFERS",
111 ok ? "PASS" : "FAIL");
112 return ok ? 0 : 1;
113}
114
115// The agglomerated bottom's own CG (CutcellMG::pcgAmg) on a round-off rhs. A constant rhs is pure
116// null space; the per-component projection subtracts a ROUNDED mean, and where the 8-fold sum
117// rounds it leaves an exactly constant residual one ulp wide (coupling's uniform porous bed:
118// 8 x -0x1.ffffffffffffcp-103 -> 8 x 0x1p-154). The AMG maps that to z = 0 and the CG's first
119// step was rz / pAp = 0/0: a NaN bottom correction, which the outer PCG reported as a non-finite
120// preconditioner and a CAPPED solve. The V-cycle is applied directly on a one-level 2^3 hierarchy
121// whose only level IS the agglomerated bottom, so the rhs reaches pcgAmg bit for bit; the
122// constant's low bits are swept so that some 8-fold sums round. Every correction must be finite.
123int roundoffBottom() {
124 const int n = 2, G = CutcellMG::G;
125 const C3 e{n + 2 * G, n + 2 * G, n + 2 * G};
126 const std::size_t cells = (std::size_t)e.x * e.y * e.z;
127 CCField one("one", cells);
128 Kokkos::deep_copy(one, 1.0);
129 CutcellMG mg;
130 mg.init(n, n, n, 1);
132 mg.setOpenness(CCConst(one), CCConst(one), CCConst(one), 1.0, 1.0, 1.0);
133 CCField r("r", cells), z("z", cells);
134 int bad = 0;
135 for (int k = 1; k <= 64; ++k) {
136 const double c = -std::ldexp(1.0 - (double)k * 0x1p-52, -102); // k = 2: the bed's value
137 auto hr = Kokkos::create_mirror_view(r);
138 for (std::size_t i = 0; i < cells; ++i)
139 hr(i) = 0.0;
140 for (int zz = G; zz < e.z - G; ++zz)
141 for (int yy = G; yy < e.y - G; ++yy)
142 for (int xx = G; xx < e.x - G; ++xx)
143 hr((std::size_t)xx + (std::size_t)yy * e.x + (std::size_t)zz * e.x * e.y) = c;
144 Kokkos::deep_copy(r, hr);
145 mg.precondVcycle(z, r);
146 auto hz = Kokkos::create_mirror_view(z);
147 Kokkos::deep_copy(hz, z);
148 bool finite = true;
149 for (std::size_t i = 0; i < cells; ++i)
150 finite = finite && std::isfinite(hz(i));
151 if (!finite) {
152 if (bad < 4)
153 std::printf(" constant bottom rhs %a: non-finite correction\n", c);
154 ++bad;
155 }
156 }
157 std::printf(
158 " round-off constant rhs on the agglomerated bottom: %d/64 corrections non-finite"
159 " -> %s\n",
160 bad, bad ? "FAIL" : "PASS");
161 return bad ? 1 : 0;
162}
163
164} // namespace
165
166int main(int argc, char** argv) {
167 Kokkos::initialize(argc, argv);
168 int fails = 0;
169 {
170 std::printf("=== pcg_breakdown (A6 exits, doc/vof_step_performance_design.md §5.6) ===\n");
171 const Problem P = makeProblem();
172 const int K = 3, M = 6;
173 const Result refK = solve(P, K, 0, -1), refK1 = solve(P, K + 1, 0, -1);
174 const Result refM = solve(P, M, 0, -1);
175 std::printf(" references: maxit %d -> it %d, maxit %d -> it %d, maxit %d -> it %d\n", K,
176 refK.it, K + 1, refK1.it, M, refM.it);
177 if (refK.it != K || refK1.it != K + 1 || refM.it != M || refK.failed || refM.failed) {
178 std::printf(" FAIL: the reference solves must run to their caps unfailed\n");
179 ++fails;
180 }
181 fails += check("NaN pAp at iteration 3", solve(P, M, 1, K), K, true, refK);
182 fails += check("NaN r^T z at iteration 3", solve(P, M, 2, K), K, true, refK1);
183 fails +=
184 check("NaN r^T z at the last iteration (maxit 4)", solve(P, K + 1, 2, K), K, true, refK1);
185 fails += check("NaN pAp at iteration 0", solve(P, M, 1, 0), 0, true, solve(P, 0, 0, -1));
187 std::printf("%s\n", fails ? "pcg_breakdown: FAIL" : "pcg_breakdown: PASS");
188 }
189 Kokkos::finalize();
190 return fails ? 1 : 0;
191}
void setDebugBreakdown(int which, int iter)
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 setOpenness(CCConst ox, CCConst oy, CCConst oz, double idx2, double idy2, double idz2)
void precondVcycle(CCField zz, CCField rr)
static constexpr int G
void setAgglomerationMode(int mode)
void init(int nx, int ny, int nz, int nLevels)
int main()
Definition dbg_scene.cpp:13
flow — portable (Kokkos) geometric multigrid for the cut-cell (variable-openness) pressure Poisson.
x
Definition cmp.py:24
y
Definition cmp.py:24
Kokkos::View< double *, CCMem > CCField
Kokkos::View< const double *, CCMem > CCConst
one(timed)
Definition prof.py:109
solve(N, kind, mu=0.1, F=1e-3, dt=80.0, warm_tol=1e-7, tail=40, max_steps=4000)
Kokkos::View< double *, Kokkos::HostSpace > x
static constexpr int G
static double mean(const std::vector< double > &a)