rtx-cfd: overset momentum residual carries its pieces per ring face (time, convective, diffusive, pressure); overset_cfd1 offline probes on the saved fields — RTX_OVERSET_CFD1_FRONT dumps the cylinder-front faces by piece, RTX_OVERSET_CFD1_RAW re-evaluates the ring on the raw interpolated stamping without balance_fringe_fluxes (the balance is not the ring's source: +0.241 raw vs +0.247 balanced at ny = 41 upwind)
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Build (ubuntu-latest) (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Test (macos-latest) (push) Canceled after 0s
CI / Test (ubuntu-latest) (push) Canceled after 0s
CI / Build CPU-Only (Explicit) (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
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01X2GmJXeQ2njUecEKiJZ1G2
This commit is contained in:
Omar Sobh
2026-09-06 14:37:08 -07:00
co-authored by Claude Fable 5.1
parent 0215c7d6a5
commit 4c000266d9
2 changed files with 177 additions and 0 deletions
@@ -366,6 +366,129 @@ async fn run_cfd1(ny: usize, max_steps: usize) -> CfdResult<Cfd1> {
mr.interface_u,
mr.interface_v
);
// `RTX_OVERSET_CFD1_FRONT=1`: every prescribed u face with x < 0.20
// (the cylinder front, where the ring's source sits) with the pieces
// of its residual, and the band's sums by piece.
if std::env::var("RTX_OVERSET_CFD1_FRONT").is_ok() {
let mut sums = [0.0_f64; 4];
let mut consistency = 0.0_f64;
for f in mr
.prescribed
.iter()
.filter(|f| f.is_u && f.r.is_finite() && (f.i as f64) * h < 0.20)
{
let pc = f.pieces;
let recon = pc[0] + pc[1] - pc[2] + pc[3];
consistency = consistency.max((recon - f.r).abs());
for k in 0..4 {
sums[k] += pc[k];
}
let cls = |jj: usize, ii: usize| {
format!("{:?}", solver.overlap().class(jj, ii))
.chars()
.next()
.unwrap()
};
println!(
" front u face j {:2} i {:2} (x {:.3} y {:.3}) {}|{}: r {:+.4e} = time {:+.2e} + conv {:+.2e} diff {:+.2e} + pres {:+.2e} u_old {:+.4} u {:+.4}",
f.j,
f.i,
f.i as f64 * h,
(f.j as f64 + 0.5) * h,
cls(f.j, f.i - 1),
cls(f.j, f.i),
f.r,
pc[0],
pc[1],
pc[2],
pc[3],
field.background.u_old[(f.j, f.i)],
field.background.u[(f.j, f.i)]
);
}
println!(
" front band sums: time {:+.4} conv {:+.4} diff {:+.4} pres {:+.4} (pieces reconstruct r to {:.1e})",
sums[0], sums[1], -sums[2], sums[3], consistency
);
}
// `RTX_OVERSET_CFD1_RAW=1`: the same ring residual on the RAW
// interpolated stamping — the prescribed faces re-stamped from the
// patch without `balance_fringe_fluxes` (u and u_old alike) — against
// the balanced one, and how far the balance moved the faces. If the
// ring's source is the balance's, the raw residual is small.
if std::env::var("RTX_OVERSET_CFD1_RAW").is_ok() {
let mut raw = OversetField {
background: field.background.clone(),
patch: field.patch.clone(),
};
solver
.overlap()
.stamp_fringe_faces(&mut raw.background, &field.patch.u, &field.patch.v);
let (mut moved, mut moved_max, mut scale) = (0.0_f64, 0.0_f64, 0.0_f64);
for e in &solver.overlap().fringe_u {
let d = raw.background.u[(e.j, e.i)] - field.background.u[(e.j, e.i)];
moved += d.abs();
moved_max = moved_max.max(d.abs());
scale = scale.max(field.background.u[(e.j, e.i)].abs());
}
for e in &solver.overlap().fringe_v {
let d = raw.background.v[(e.j, e.i)] - field.background.v[(e.j, e.i)];
moved += d.abs();
moved_max = moved_max.max(d.abs());
}
raw.background.u_old.copy_from(&raw.background.u);
raw.background.v_old.copy_from(&raw.background.v);
// Active faces keep u_old = u^n; only the prescribed faces changed.
for j in 0..field.background.u.nrows() {
for i in 0..field.background.u.ncols() {
if solver.background().mask().expect("mask").u_kind(j, i)
== rtx_cfd::solvers::incompressible::FaceKind::Fluid
{
raw.background.u_old[(j, i)] = field.background.u_old[(j, i)];
raw.background.u[(j, i)] = field.background.u[(j, i)];
}
}
}
for j in 0..field.background.v.nrows() {
for i in 0..field.background.v.ncols() {
if solver.background().mask().expect("mask").v_kind(j, i)
== rtx_cfd::solvers::incompressible::FaceKind::Fluid
{
raw.background.v_old[(j, i)] = field.background.v_old[(j, i)];
raw.background.v[(j, i)] = field.background.v[(j, i)];
}
}
}
let mr_raw = solver.momentum_residual(&raw, dt);
let mut front_raw = 0.0;
for f in mr_raw
.prescribed
.iter()
.filter(|f| f.is_u && f.r.is_finite() && (f.i as f64) * h < 0.20)
{
front_raw += f.r;
}
println!(
" raw-stamping ring residual ny = {ny}: fringefringe ({:+.4}, {:+.4}) fringehole ({:+.4}, {:+.4}) ring total x {:+.4} (balanced {:+.4}); front band x {:+.4} (balanced {:+.4}); the balance moved the prescribed faces by Σ|Δu| {:.3e} max {:.3e} (max |u| {:.3}); background mass defect raw {:.3e} balanced {:.3e}",
mr_raw.fringe_fringe.fx,
mr_raw.fringe_fringe.fy,
mr_raw.fringe_hole.fx,
mr_raw.fringe_hole.fy,
mr_raw.fringe_fringe.fx + mr_raw.fringe_hole.fx,
mr.fringe_fringe.fx + mr.fringe_hole.fx,
front_raw,
mr.prescribed
.iter()
.filter(|f| f.is_u && f.r.is_finite() && (f.i as f64) * h < 0.20)
.map(|f| f.r)
.sum::<f64>(),
moved,
moved_max,
scale,
solver.overlap().background_mass_defect(&raw.background),
solver.overlap().background_mass_defect(&field.background),
);
}
// The box force in the solver's own flux form on the five boxes (must
// agree to rounding — the gate), and the bookkeeping it allows: the
// numerical x-momentum source inside the box on the fluid is