flow 0.4.0
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
ghost_projection_debug.hpp
Go to the documentation of this file.
1
28#ifndef PECLET_FLOW_GHOST_PROJECTION_DEBUG_HPP
29#define PECLET_FLOW_GHOST_PROJECTION_DEBUG_HPP
30
31#include <Kokkos_Core.hpp>
32
33#include <algorithm>
34#include <cmath>
35#include <cstdint>
36#include <cstdio>
37#include <cstdlib>
38#include <string>
39#include <vector>
40
41#include "ghost_projection.hpp"
42
43namespace peclet::flow {
44
46inline int gpDebugLevel() {
47 const char* s = std::getenv("PECLET_FLOW_GP_DEBUG");
48 return s ? std::atoi(s) : 0;
49}
50
54inline void gpDebugReport(const GpOverlay& ov, int nRows, C3 nn,
55 Kokkos::View<int*, CCMem> idMap, int rank = 0) {
56 const int level = gpDebugLevel();
57 if (level <= 0 || nRows <= 0)
58 return;
59 const auto h_cell = Kokkos::create_mirror_view_and_copy(
60 Kokkos::HostSpace(), Kokkos::subview(ov.cell, Kokkos::make_pair(0, nRows)));
61 const auto h_rho = Kokkos::create_mirror_view_and_copy(
62 Kokkos::HostSpace(), Kokkos::subview(ov.rescale, Kokkos::make_pair(0, nRows)));
63 const auto h_cpl = Kokkos::create_mirror_view_and_copy(
64 Kokkos::HostSpace(), Kokkos::subview(ov.coupled, Kokkos::make_pair(0, nRows)));
65 const auto sub6 = Kokkos::make_pair(0, 6 * nRows);
66 const auto h_st = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
67 Kokkos::subview(ov.state, sub6));
68 const auto h_th =
69 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), Kokkos::subview(ov.th, sub6));
70 const auto h_wm1 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
71 Kokkos::subview(ov.wm_n1, sub6));
72 const auto h_wm2 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
73 Kokkos::subview(ov.wm_n2, sub6));
74 const auto h_w1 =
75 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), Kokkos::subview(ov.w_n1, sub6));
76 const auto h_w2 =
77 Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), Kokkos::subview(ov.w_n2, sub6));
78 const auto h_id = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), idMap);
79
80 const char* stName[5] = {"COUPLED", "QUAD", "LIN", "BC_ONLY", "EXPLICIT"};
81 long stCount[5] = {0, 0, 0, 0, 0};
82 long extendedTh = 0, clampedThLo = 0, clampedThHi = 0;
83 // rho decades: [1e-5,1e-4) ... [1e-1,1) and == 1
84 long rhoDec[7] = {0, 0, 0, 0, 0, 0, 0};
85 long wDec[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // max |w| decades 1e0..1e7
86 long decoupled = 0;
87 double rhoMin = 1.0, wMax = 0.0;
88
89 std::vector<float> rowMaxW((std::size_t)nRows, 0.0f);
90 for (int s = 0; s < nRows; ++s) {
91 if (!h_cpl(s))
92 ++decoupled;
93 const float rho = h_rho(s);
94 rhoMin = rho < rhoMin ? rho : rhoMin;
95 int d = rho >= 1.0f ? 6 : (int)std::floor(std::log10((double)rho)) + 6;
96 rhoDec[d < 0 ? 0 : (d > 6 ? 6 : d)]++;
97 float mw = 0.0f;
98 for (int k = 0; k < 6; ++k) {
99 const int8_t st = h_st(s * 6 + k);
100 stCount[st < 0 || st > 4 ? 0 : st]++;
101 const float th = h_th(s * 6 + k);
102 if (st == GP_QUAD || st == GP_LIN) {
103 if (th > 1.0f)
104 ++extendedTh;
105 if (th <= (float)(1e-4 * 1.0000001))
106 ++clampedThLo;
107 if (th >= 2.0f)
108 ++clampedThHi;
109 const float a1 = std::fabs(h_wm1(s * 6 + k)), a2 = std::fabs(h_wm2(s * 6 + k));
110 mw = mw > a1 ? mw : a1;
111 mw = mw > a2 ? mw : a2;
112 const float b1 = std::fabs(h_w1(s * 6 + k)), b2 = std::fabs(h_w2(s * 6 + k));
113 mw = mw > b1 ? mw : b1;
114 mw = mw > b2 ? mw : b2;
115 }
116 }
117 rowMaxW[(std::size_t)s] = mw;
118 wMax = mw > wMax ? mw : wMax;
119 int wd = mw <= 1.0f ? 0 : (int)std::floor(std::log10((double)mw));
120 wDec[wd < 0 ? 0 : (wd > 7 ? 7 : wd)]++;
121 }
122
123 // Neighbour rho mismatch: the row scaling is a LEFT diagonal scaling of a nonsymmetric operator,
124 // so a row whose rho differs sharply from its neighbours' has coefficients a_ij / a_ji differing
125 // by that ratio. Cells with no overlay row scale by 1.
126 const long nInner = (long)nn.x * nn.y * nn.z;
127 long mmDec[6] = {0, 0, 0, 0, 0, 0}; // |log10 ratio| in [0,1),[1,2),...,[5,inf)
128 double mmMax = 0.0;
129 auto rhoAt = [&](int x, int y, int z) -> float {
130 const int ix = ((x % nn.x) + nn.x) % nn.x, iy = ((y % nn.y) + nn.y) % nn.y,
131 iz = ((z % nn.z) + nn.z) % nn.z;
132 const long c = (long)ix + (long)iy * nn.x + (long)iz * (long)nn.x * nn.y;
133 if (c < 0 || c >= nInner)
134 return 1.0f;
135 const int s = h_id(c);
136 return s >= 0 ? h_rho(s) : 1.0f;
137 };
138 std::vector<float> rowMismatch((std::size_t)nRows, 0.0f);
139 for (int s = 0; s < nRows; ++s) {
140 const int c = h_cell(s);
141 const int x = c % nn.x, y = (c / nn.x) % nn.y, z = c / (nn.x * nn.y);
142 const double lr = std::log10((double)h_rho(s));
143 double worst = 0.0;
144 const int off[6][3] = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}};
145 for (auto& o : off) {
146 const double d = std::fabs(lr - std::log10((double)rhoAt(x + o[0], y + o[1], z + o[2])));
147 worst = d > worst ? d : worst;
148 }
149 rowMismatch[(std::size_t)s] = (float)worst;
150 mmMax = worst > mmMax ? worst : mmMax;
151 int b = (int)worst;
152 mmDec[b < 0 ? 0 : (b > 5 ? 5 : b)]++;
153 }
154
155 std::printf("[gp] rank %d overlay census: %d rows of %ld inner cells (%.2f %%), %ld decoupled\n",
156 rank, nRows, nInner, 100.0 * nRows / (double)nInner, decoupled);
157 std::printf("[gp] face states:");
158 for (int i = 0; i < 5; ++i)
159 std::printf(" %s=%ld", stName[i], stCount[i]);
160 std::printf("\n[gp] theta: EXTENDED(1,2)=%ld clamped-low(1e-4)=%ld clamped-high(2)=%ld\n",
162 std::printf("[gp] rho decades [1e-5,1e-4)=%ld [1e-4,1e-3)=%ld [1e-3,1e-2)=%ld "
163 "[1e-2,1e-1)=%ld [1e-1,1)=%ld ==1:%ld min=%.3e\n",
164 rhoDec[0] + rhoDec[1], rhoDec[2], rhoDec[3], rhoDec[4], rhoDec[5], rhoDec[6], rhoMin);
165 std::printf("[gp] max|w| decades");
166 for (int i = 0; i < 8; ++i)
167 std::printf(" 1e%d:%ld", i, wDec[i]);
168 std::printf(" max=%.3e\n", wMax);
169 std::printf("[gp] neighbour rho mismatch |log10| bins");
170 for (int i = 0; i < 6; ++i)
171 std::printf(" %d:%ld", i, mmDec[i]);
172 std::printf(" max=%.2f decades\n", mmMax);
173
174 // the 20 worst rows by rho, with their full face anatomy
175 std::vector<int> ord((std::size_t)nRows);
176 for (int i = 0; i < nRows; ++i)
177 ord[(std::size_t)i] = i;
178 const int show = nRows < 20 ? nRows : 20;
179 std::partial_sort(ord.begin(), ord.begin() + show, ord.end(),
180 [&](int a, int b) { return h_rho(a) < h_rho(b); });
181 std::printf("[gp] worst %d rows by rho:\n", show);
182 for (int i = 0; i < show; ++i) {
183 const int s = ord[(std::size_t)i];
184 const int c = h_cell(s);
185 std::printf("[gp] (%4d,%4d,%4d) rho=%.4e maxw=%.3e mism=%.2f |", c % nn.x,
186 (c / nn.x) % nn.y, c / (nn.x * nn.y), h_rho(s), rowMaxW[(std::size_t)s],
187 rowMismatch[(std::size_t)s]);
188 for (int k = 0; k < 6; ++k)
189 std::printf(" %s(th=%.3e,wm=%.3e/%.3e)", stName[h_st(s * 6 + k)], h_th(s * 6 + k),
190 h_wm1(s * 6 + k), h_wm2(s * 6 + k));
191 std::printf("\n");
192 }
193 std::fflush(stdout);
194
195 if (level < 2)
196 return;
197 const char* fenv = std::getenv("PECLET_FLOW_GP_DEBUG_FILE");
198 std::string path = fenv ? std::string(fenv) : std::string("gp_rows");
199 path += "_rank" + std::to_string(rank) + ".bin";
200 std::FILE* f = std::fopen(path.c_str(), "wb");
201 if (!f) {
202 std::printf("[gp] COULD NOT OPEN %s for the per-row dump\n", path.c_str());
203 return;
204 }
205 for (int s = 0; s < nRows; ++s) {
206 const int c = h_cell(s);
207 const int32_t xyz[3] = {c % nn.x, (c / nn.x) % nn.y, c / (nn.x * nn.y)};
208 const float rho = h_rho(s);
209 const int8_t cpl = h_cpl(s);
210 int8_t st[6];
211 float th[6], wm1[6], wm2[6], w1[6], w2[6];
212 for (int k = 0; k < 6; ++k) {
213 st[k] = h_st(s * 6 + k);
214 th[k] = h_th(s * 6 + k);
215 wm1[k] = h_wm1(s * 6 + k);
216 wm2[k] = h_wm2(s * 6 + k);
217 w1[k] = h_w1(s * 6 + k);
218 w2[k] = h_w2(s * 6 + k);
219 }
220 std::fwrite(xyz, sizeof(int32_t), 3, f);
221 std::fwrite(&rho, sizeof(float), 1, f);
222 std::fwrite(&cpl, sizeof(int8_t), 1, f);
223 std::fwrite(st, sizeof(int8_t), 6, f);
224 std::fwrite(th, sizeof(float), 6, f);
225 std::fwrite(wm1, sizeof(float), 6, f);
226 std::fwrite(wm2, sizeof(float), 6, f);
227 std::fwrite(w1, sizeof(float), 6, f);
228 std::fwrite(w2, sizeof(float), 6, f);
229 }
230 std::fclose(f);
231 std::printf("[gp] per-row dump -> %s (%d records)\n", path.c_str(), nRows);
232 std::fflush(stdout);
233}
234
235} // namespace peclet::flow
236
237#endif // PECLET_FLOW_GHOST_PROJECTION_DEBUG_HPP
flow — directional ghost-cell IBM projection overlay (experimental second staggered IBM).
int gpDebugLevel()
0 = off (default). Read once per call; cheap enough, and keeps the flag hot-swappable in tests.
void gpDebugReport(const GpOverlay &ov, int nRows, C3 nn, Kokkos::View< int *, CCMem > idMap, int rank=0)
Census + optional per-row dump of the built overlay.
void ibmFillEntry(const OV &o, int list_idx, int c_idx, float sdf_c, const float sdf_n[6], int bc_type, const float *thEx)
Kokkos::View< int8_t *, Space > state
Kokkos::View< float *, Space > w_n1
Kokkos::View< int *, Space > cell
Kokkos::View< float *, Space > w_n2
Kokkos::View< float *, Space > wm_n1
Kokkos::View< float *, Space > rescale
Kokkos::View< float *, Space > th
Kokkos::View< int8_t *, Space > coupled
Kokkos::View< float *, Space > wm_n2
static double rhoAt(int, int, int z)