embedded3 S2-6: the oblique-wall instrument (tests/embedded3_wall_position_oblique.rs: z-flow / in-plane Poiseuille + Couette linear exactness; gate oblique_wall_position_is_second_order) and the closures it found, host + device, default OFF — the transverse centroid correction (RTX_E3_DIFFUSION_TRANSVERSE=1, wall_order bit 7), the fine distance floor (RTX_E3_DISTANCE_FLOOR=fine, bit 8); kernel geometry factored into cut_cv; DFG 2D-1 x-shift knob (RTX_E3_DFG_SHIFT_X); FLAG_X0 0.6 -> 0.25 in the three flag tests (the flag of every record was detached)
CI / Format Check (push) Failing after 5s
CI / Clippy Check (push) Failing after 5s
CI / Build (ubuntu-latest) (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 6s
Documentation / Build API Documentation (push) Failing after 17s
CI / Build CPU-Only (Explicit) (push) Failing after 57s
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 16:22:38 -05:00
co-authored by Claude Fable 5.1
parent 9ae0e42dcd
commit e9b2e7887b
12 changed files with 579 additions and 24 deletions
@@ -17,6 +17,15 @@ impl Mask {
[t[c][3 * f], t[c][3 * f + 1], t[c][3 * f + 2]]
}
/// The wall-distance floor in units of the smallest spacing (S2-6).
pub(super) fn distance_floor(&self) -> f64 {
if self.distance_floor_fine {
super::cutwall::DISTANCE_FLOOR_FINE
} else {
super::cutwall::DISTANCE_FLOOR
}
}
/// The per-face shift tables (three components interleaved).
#[must_use]
pub fn face_shift_tables(&self) -> Option<&[Vec<f64>; 3]> {
@@ -25,6 +25,8 @@ use super::wall::{FaceKind, Mask};
pub(super) const INERTIA_FLOOR: f64 = 0.1;
/// The wall-distance floor of a face, in units of the smallest spacing.
pub(super) const DISTANCE_FLOOR: f64 = 0.05;
/// The fine floor (S2-6, `Parameters::distance_floor_fine`).
pub(super) const DISTANCE_FLOOR_FINE: f64 = 0.01;
/// Virtual merging: a cell whose fluid fraction (at either end of the
/// step) stays below this shares its pressure unknown with a neighbour.
pub(super) const MERGE_FRACTION: f64 = 0.1;
@@ -211,6 +213,8 @@ impl Mask {
density: 1.0,
wall_order: 1,
wall_distance_oblique: false,
diffusion_transverse: false,
distance_floor_fine: false,
wall_exchange_axis: false,
grad_weights: None,
diffusion_centroid: false,
@@ -398,7 +402,8 @@ impl Mask {
} else {
1.0
};
let distance = (phi_face + 0.5 * h[c] * (1.0 - alpha) * n_t).max(DISTANCE_FLOOR * h_min);
let distance =
(phi_face + 0.5 * h[c] * (1.0 - alpha) * n_t).max(self.distance_floor() * h_min);
CvGeometry {
alpha,
ap,
@@ -197,6 +197,54 @@ impl Solver {
delta.clamp(0.25 * h[d], 2.0 * h[d])
};
let solid = |q: [i64; 3]| mask.wall_exchange_axis && ap(c, q) == Some(0.0);
// S2-6: the centroids of two neighbours with different apertures
// are offset ACROSS the difference's axis (in the cross and in
// the own direction); the two-point difference then carries
// `∇u · Δs_⊥`, removed with the cut faces' own wall-normal
// gradients `(u − U_b)/d_f` (old values: explicit).
let transverse = |q: [i64; 3], uq: f64, sign: f64| -> f64 {
let sq = mask.face_shift(c, q);
let mut ds = [0.0; 3];
for e2 in 0..3 {
if e2 != d {
ds[e2] = sign * (sq[e2] - shift0[e2]);
}
}
if ds == [0.0; 3] {
return 0.0;
}
let cvq = mask.cv_geometry(c, q);
let ubq = mask.surface_velocity_at(body, lat.face_position(c, q), c, t_old);
let mut g = [0.0; 3];
let mut count = 0.0;
for (cvk, uk, ubk) in [(&cv, u0, ub), (&cvq, uq, ubq)] {
let a = (cvk.wall[0] * cvk.wall[0]
+ cvk.wall[1] * cvk.wall[1]
+ cvk.wall[2] * cvk.wall[2])
.sqrt();
if a > 0.0 && cvk.alpha < 1.0 {
let slope = (uk - ubk) / (cvk.distance * a);
for e2 in 0..3 {
g[e2] -= slope * cvk.wall[e2];
}
count += 1.0;
}
}
if count == 0.0 {
return 0.0;
}
(g[0] * ds[0] + g[1] * ds[1] + g[2] * ds[2]) / count
};
if mask.diffusion_transverse {
for (nb, sign, gap) in [(up1, 1.0, g_plus), (dn1, -1.0, g_minus)] {
let q = add(p, ed, sign as i64);
let Some(uq) = nb else { continue };
if solid(q) || !ap(c, q).is_some_and(|a| a > 0.0) {
continue;
}
diff -= sign * mu * gap * a_d * transverse(q, uq, sign) / spacing(q, sign);
}
}
diff += match up1 {
Some(un) if solid(add(p, ed, 1)) => {
let k = mu * g_plus * a_d / mask.exchange_delta(&cv, d);
@@ -292,7 +292,14 @@ impl DeviceStep {
wall_order: i32::from(self.solver.params.wall_order)
+ 16 * i32::from(self.solver.params.wall_distance_oblique)
+ 32 * i32::from(self.solver.params.wall_exchange_axis)
+ 64 * i32::from(self.solver.params.diffusion_centroid),
+ 64 * i32::from(self.solver.params.diffusion_centroid)
// bit 7: the transverse centroid correction; bit 8: the fine floor (S2-6).
+ 128
* i32::from(
self.solver.params.diffusion_transverse
&& self.solver.params.diffusion_centroid,
)
+ 256 * i32::from(self.solver.params.distance_floor_fine),
dx: g.dx,
dy: g.dy,
dz: g.dz,
@@ -102,6 +102,18 @@ pub struct Parameters {
/// by `½h(1 − α)(1 − |n_t|)` at every h (S2-5). `Parameters::default()`
/// reads `RTX_E3_WALL_DISTANCE=oblique` (default: the recorded form).
pub wall_distance_oblique: bool,
/// The transverse part of the centroid diffusion (S2-6): two neighbour
/// faces with different apertures have open-part centroids offset
/// ACROSS the axis of their difference, so the two-point difference
/// carries `∇u · Δs_⊥` — a first-order wall position on oblique walls
/// (≈ 0.1 h inside the body). Removed with the faces' own wall-normal
/// gradients `(u − U_b)/d_f`, in the cross AND the own direction.
/// Needs `diffusion_centroid`. `RTX_E3_DIFFUSION_TRANSVERSE=1`.
pub diffusion_transverse: bool,
/// The wall-distance floor at 0.01 of the smallest spacing instead of
/// 0.05: the coarse floor doubles the distance of faces with α < 0.1
/// (the flat wall's θ 0.95 excess, S2-6). `RTX_E3_DISTANCE_FLOOR=fine`.
pub distance_floor_fine: bool,
/// The diffusive exchange of a fluid face with a SOLID neighbour face
/// over the axis distance to the wall, `δ = min(h, d_f/|n_d|)`, and
/// implicit — instead of the full `h`, which places the no-slip value
@@ -145,6 +157,9 @@ impl Default for Parameters {
.unwrap_or(1),
wall_distance_oblique: std::env::var("RTX_E3_WALL_DISTANCE")
.is_ok_and(|v| v == "oblique"),
diffusion_transverse: std::env::var("RTX_E3_DIFFUSION_TRANSVERSE")
.is_ok_and(|v| v == "1"),
distance_floor_fine: std::env::var("RTX_E3_DISTANCE_FLOOR").is_ok_and(|v| v == "fine"),
wall_exchange_axis: std::env::var("RTX_E3_WALL_EXCHANGE").is_ok_and(|v| v == "axis"),
pressure_centroid: std::env::var("RTX_E3_PRESSURE_CENTROID").is_ok_and(|v| v == "1"),
// ON by default since S2-5 (`=0` reproduces the records before it).
@@ -281,6 +296,9 @@ impl Solver {
m.wall_order = self.params.wall_order;
m.wall_distance_oblique = self.params.wall_distance_oblique;
m.wall_exchange_axis = self.params.wall_exchange_axis;
m.diffusion_transverse =
self.params.diffusion_transverse && self.params.diffusion_centroid;
m.distance_floor_fine = self.params.distance_floor_fine;
m.diffusion_centroid = self.params.diffusion_centroid;
if self.params.diffusion_centroid {
m.compute_face_shifts();
@@ -101,6 +101,9 @@ pub struct Mask {
pub(super) wall_order: u8,
/// The oblique wall distance of the cut faces (S2-5).
pub(super) wall_distance_oblique: bool,
/// The transverse centroid correction and the fine distance floor (S2-6).
pub(super) diffusion_transverse: bool,
pub(super) distance_floor_fine: bool,
/// The axis-distance implicit wall exchange (S2-5).
pub(super) wall_exchange_axis: bool,
/// The centroid prototype's pressure-gradient weights per u / v / w face.
@@ -524,6 +527,8 @@ impl Mask {
density: 1.0,
wall_order: 1,
wall_distance_oblique: false,
diffusion_transverse: false,
distance_floor_fine: false,
wall_exchange_axis: false,
grad_weights: None,
diffusion_centroid: false,