embedded3 S2-6: the transverse gradient from the face at least 0.2 h off the wall (full neighbours over their own distance along the cut partner's normal) — the first form blew up at DFG ny 61 with the fine floor (coefficient ~ 1/d_f); host = device 7.7e-14 with the closures on; Couette linear exactness kept (<= 0.01 h); RTX_E3_OBLIQUE_N rung knob
CI / Format Check (push) Failing after 4s
CI / Clippy Check (push) Failing after 4s
CI / Build (ubuntu-latest) (push) Failing after 5s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 7s
CI / Build CPU-Only (Explicit) (push) Failing after 49s
Documentation / Build API Documentation (push) Failing after 1m1s
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:54:52 -05:00
co-authored by Claude Fable 5.1
parent e9b2e7887b
commit 9c3fac0755
3 changed files with 55 additions and 17 deletions
@@ -5,6 +5,10 @@
use super::cutwall::CvGeometry;
use super::wall::Mask;
/// The distance floor inside the explicit transverse gradient (S2-6), in
/// units of the smallest spacing.
pub(in crate::solvers::incompressible::embedded3) const TRANSVERSE_DISTANCE_FLOOR: f64 = 0.2;
impl Mask {
/// The shift of a face's open-part centroid from the face centre:
/// `½h(1 − α)` along the wall normal's in-plane part, away from the
@@ -11,6 +11,8 @@
//! carries the inertia floor.
use super::{Side, Solver};
use crate::solvers::incompressible::embedded3::closure::TRANSVERSE_DISTANCE_FLOOR;
use crate::solvers::incompressible::embedded3::cutwall::CvGeometry;
use crate::solvers::incompressible::embedded3::cutwall::INERTIA_FLOOR;
use crate::solvers::incompressible::embedded3::field::Field;
use crate::solvers::incompressible::simple::ConvectionScheme;
@@ -202,6 +204,7 @@ impl Solver {
// 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 h_min = h[0].min(h[1]).min(h[2]);
let transverse = |q: [i64; 3], uq: f64, sign: f64| -> f64 {
let sq = mask.face_shift(c, q);
let mut ds = [0.0; 3];
@@ -215,20 +218,37 @@ impl Solver {
}
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)] {
// Explicit, with a coefficient ∝ 1/d_f: take the gradient from
// the faces at least TRANSVERSE_DISTANCE_FLOOR h off the wall —
// a FULL neighbour too, over its own distance along the cut
// partner's normal (a linear field gives the same gradient on
// every one of them); only when neither is that far, from the
// cut faces over the floored distance.
let d_min = TRANSVERSE_DISTANCE_FLOOR * h_min;
let unit = |cvk: &CvGeometry| {
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;
(a > 0.0 && cvk.alpha < 1.0)
.then(|| [cvk.wall[0] / a, cvk.wall[1] / a, cvk.wall[2] / a])
};
let (n0, nq) = (unit(&cv), unit(&cvq));
let faces = [(&cv, u0, ub, n0.or(nq)), (&cvq, uq, ubq, nq.or(n0))];
let far = faces.iter().any(|f| f.3.is_some() && f.0.distance >= d_min);
let mut g = [0.0; 3];
let mut count = 0.0;
for (cvk, uk, ubk, normal) in faces {
let Some(nk) = normal else { continue };
let is_cut = unit(cvk).is_some();
if far && cvk.distance < d_min || !far && !is_cut {
continue;
}
let slope = (uk - ubk) / cvk.distance.max(d_min);
for e2 in 0..3 {
g[e2] -= slope * nk[e2];
}
count += 1.0;
}
if count == 0.0 {
return 0.0;