embedded3 S2-5: the cut wall sat ½(1−α)h inside the body — cross diffusion over the open-part centroid spacing (RTX_E3_DIFFUSION_CENTROID; host + e3_cut.cu, shift tables, point-implicit excess); flat-wall effective-position instrument; DFG 2D-1 ladder tests (device + host); knobs tried and refuted along the way (oblique distance, axis exchange, centroid pressure gradient)
Documentation / Build API Documentation (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 4s
CI / Clippy Check (push) Failing after 2m24s
CI / Build CPU-Only (Explicit) (push) Failing after 3s
CI / Format Check (push) Failing after 11s
CI / Build (ubuntu-latest) (push) Failing after 1m58s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m44s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Python Bindings (maturin) (ubuntu-latest) (push) Canceled after 0s
CI / WASM Build + Size Check (push) Canceled after 0s
CI / Distributed Training Tests (push) Canceled after 0s
CI / CI Success (push) Canceled after 0s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-18 10:54:52 -05:00
co-authored by Claude Fable 5.1
parent 4c3e58fa27
commit fdfb6da769
12 changed files with 667 additions and 22 deletions
@@ -26,6 +26,7 @@ struct E3Cut {
const unsigned int *owner; /* the master of a merged cell (itself otherwise) */
const unsigned int *fold_ptr, *fold_idx; /* CSR: the slaves of every cell */
double *cell_flux; /* scratch per cell */
const double *s_u, *s_v, *s_w; /* open-part centroid shifts per face, 3 interleaved (S2-5) */
};
/* Face index of component c at lattice (i, j, k); 1 outside (z wraps when periodic). */
@@ -95,14 +96,20 @@ __device__ double cut_face_update(const E3Params& g, const E3Ptrs& f, const E3Cu
for (int d = 0; d < 3; ++d) wall[d] = -(app[d] - apm[d]) * area[d];
double h_min = fmin(fmin(g.dx, g.dy), g.dz);
const double* dist = c == 0 ? m.d_u : (c == 1 ? m.d_v : m.d_w);
double distance = fmax(dist[fidx] + 0.5 * h[c] * (1.0 - alpha), CUT_DISTANCE_FLOOR * h_min);
/* bit 4 of wall_order: the oblique wall distance (the in-plane part of the wall normal) */
double n_t = 1.0;
if (g.wall_order & 16) {
double a_w0 = sqrt(wall[0] * wall[0] + wall[1] * wall[1] + wall[2] * wall[2]);
if (a_w0 > 0.0) { double n_c = wall[c] / a_w0; n_t = sqrt(fmax(1.0 - n_c * n_c, 0.0)); }
}
double distance = fmax(dist[fidx] + 0.5 * h[c] * (1.0 - alpha) * n_t, CUT_DISTANCE_FLOOR * h_min);
const double* ubt = c == 0 ? m.ub_u : (c == 1 ? m.ub_v : m.ub_w);
double ub = ubt[fidx];
/* face position */
double x[3];
for (int d = 0; d < 3; ++d) x[d] = (p[d] + (d == c ? 0.0 : 0.5)) * h[d];
double mass_out = 0.0, conv = 0.0, diff = 0.0;
double mass_out = 0.0, conv = 0.0, diff = 0.0, wall_implicit = 0.0, wall_rhs = 0.0;
for (int d = 0; d < 3; ++d) {
double a_d = area[d];
int q[3];
@@ -171,9 +178,41 @@ __device__ double cut_face_update(const E3Params& g, const E3Ptrs& f, const E3Cu
conv += m_plus * (u_plus + delta_plus) - m_minus * (u_minus + delta_minus);
/* diffusion */
double g_minus = apm[d], g_plus = app[d];
if (f_up1 >= 0) diff += mu * g_plus * a_d * (up1 - u0) / h[d];
/* bit 5 of wall_order: the exchange with a SOLID neighbour over the axis
distance to the wall, implicit (S2-5) */
double delta_x = h[d];
if (g.wall_order & 32) {
double a_w0 = sqrt(wall[0] * wall[0] + wall[1] * wall[1] + wall[2] * wall[2]);
if (a_w0 > 0.0) {
double n_d = fabs(wall[d]) / a_w0;
if (n_d >= 1e-12) delta_x = fmin(distance / n_d, h[d]);
}
}
int solid_up = (g.wall_order & 32) && f_up1 >= 0 && cut_ap(m, c)[f_up1] == 0.0;
int solid_dn = (g.wall_order & 32) && f_dn1 >= 0 && cut_ap(m, c)[f_dn1] == 0.0;
/* bit 6 of wall_order: cross diffusion over the open-part centroid spacing,
the part beyond 1/h point-implicit (S2-5) */
int centroid = (g.wall_order & 64) && d != c;
const double* sh = c == 0 ? m.s_u : (c == 1 ? m.s_v : m.s_w);
if (solid_up) { double kx = mu * g_plus * a_d / delta_x; wall_implicit += kx; wall_rhs += kx * up1; }
else if (f_up1 >= 0 && centroid) {
double dl = h[d] + (sh[3 * f_up1 + d] - sh[3 * fidx + d]);
dl = fmin(fmax(dl, 0.25 * h[d]), 2.0 * h[d]);
double kx = mu * g_plus * a_d * (1.0 / dl - 1.0 / h[d]);
if (kx > 0.0) { wall_implicit += kx; wall_rhs += kx * up1; diff += mu * g_plus * a_d * (up1 - u0) / h[d]; }
else diff += (mu * g_plus * a_d / h[d] + kx) * (up1 - u0);
}
else if (f_up1 >= 0) diff += mu * g_plus * a_d * (up1 - u0) / h[d];
else if (sides[d][1] == SIDE_VELOCITY) diff += mu * g_plus * a_d * (beyond_p - u0) / (0.5 * h[d]);
if (f_dn1 >= 0) diff -= mu * g_minus * a_d * (u0 - dn1) / h[d];
if (solid_dn) { double kx = mu * g_minus * a_d / delta_x; wall_implicit += kx; wall_rhs += kx * dn1; }
else if (f_dn1 >= 0 && centroid) {
double dl = h[d] - (sh[3 * f_dn1 + d] - sh[3 * fidx + d]);
dl = fmin(fmax(dl, 0.25 * h[d]), 2.0 * h[d]);
double kx = mu * g_minus * a_d * (1.0 / dl - 1.0 / h[d]);
if (kx > 0.0) { wall_implicit += kx; wall_rhs += kx * dn1; diff -= mu * g_minus * a_d * (u0 - dn1) / h[d]; }
else diff -= (mu * g_minus * a_d / h[d] + kx) * (u0 - dn1);
}
else if (f_dn1 >= 0) diff -= mu * g_minus * a_d * (u0 - dn1) / h[d];
else if (sides[d][0] == SIDE_VELOCITY) diff -= mu * g_minus * a_d * (u0 - beyond_m) / (0.5 * h[d]);
}
/* The mass fluxes above are volume fluxes: the momentum flux carries rho. */
@@ -191,7 +230,7 @@ __device__ double cut_face_update(const E3Params& g, const E3Ptrs& f, const E3Cu
open face away from the body along the wall normal's dominant axis
(order 2; the neighbour's old value explicit). */
double c1 = 1.0 / distance, shear_explicit = 0.0;
if (g.wall_order >= 2 && a_w > 0.0) {
if ((g.wall_order & 15) >= 2 && a_w > 0.0) {
double nw[3] = { wall[0] / a_w, wall[1] / a_w, wall[2] / a_w };
int d = 0;
for (int kk = 1; kk < 3; ++kk) if (fabs(nw[kk]) > fabs(nw[d])) d = kk;
@@ -208,7 +247,7 @@ __device__ double cut_face_update(const E3Params& g, const E3Ptrs& f, const E3Cu
double shear = mu * a_w * c1;
double v_eff = fmax(alpha, CUT_INERTIA_FLOOR) * h[c] * area[c];
double inertia = rho * v_eff / g.dt;
return (inertia * u0 - conv + diff + pressure + source + shear * ub - shear_explicit) / (inertia + shear);
return (inertia * u0 - conv + diff + pressure + source + shear * ub - shear_explicit + wall_rhs) / (inertia + shear + wall_implicit);
}
/* The predictor on the open interior faces of component c. */