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