fsi2 overset harness: RTX_FSI2O_CASE=FSI3 (the FSI3 constants with FEATFLOW level-4 references in the summary), RTX_FSI2O_SAVE_FROM (instants only from a time on — a dense last period for the viewer)
CI / Format Check (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 0s
CI / Build (ubuntu-latest) (push) Failing after 6s
CI / Build CPU-Only (Explicit) (push) Failing after 53s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build API Documentation (push) Failing after 13s
CI / Clippy Check (push) Failing after 23s
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]>
Claude-Session: https://claude.ai/code/session_01LzcjQX7tvgn87CQCyg9Cfr
This commit is contained in:
Omar Sobh
2026-09-14 06:36:45 -05:00
co-authored by Claude Fable 5.1
parent 415c32ab04
commit e54729241d
2 changed files with 74 additions and 21 deletions
@@ -283,6 +283,10 @@ pub fn run_march_overset(case: BenchmarkCase, config: &OversetMarchConfig) -> Ov
});
let (t_fluid, t_structure) = (std::cell::Cell::new(0.0_f64), std::cell::Cell::new(0.0_f64));
let prev_area = std::cell::Cell::new(fluid.borrow().shared.read().unwrap().area());
let save_from: f64 = std::env::var("RTX_FSI2O_SAVE_FROM")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(0.0);
let save_every: usize = std::env::var("RTX_FSI2O_SAVE_EVERY")
.ok()
.and_then(|v| v.parse().ok())
@@ -418,7 +422,9 @@ pub fn run_march_overset(case: BenchmarkCase, config: &OversetMarchConfig) -> Ov
fluid.borrow_mut().commit_base();
// `RTX_FSI2O_SAVE_EVERY=N` (+ `RTX_FSI2O_SAVE`): the composite at
// every N-th committed step, for the offline chain audit.
if save_every > 0 && (step + 1) % save_every == 0 {
// `RTX_FSI2O_SAVE_FROM=t` (0): instants only from t on — a dense
// last period for the viewer without a gigabyte of the onset.
if save_every > 0 && (step + 1) % save_every == 0 && t_now >= save_from {
if let Ok(dir) = std::env::var("RTX_FSI2O_SAVE") {
let d_now = extract(&flag_state);
let dd_now = extract_velocity(&flag_state);
@@ -9,21 +9,53 @@
mod fsi2_harness;
use fsi2_harness::overset_march::{OversetMarchConfig, run_march_overset};
use fsi2_harness::{FSI2, case_from_env};
use fsi2_harness::{FSI2, FSI3, case_from_env};
// Reference: FEATFLOW's FSI2 table (Turek's group), level 4, Δt = 0.01 —
// uy 1.24 ± 81.7 mm at 1.93 Hz, ux 14.87 ± 12.73 mm, drag 215.18 ± 77.78,
// lift 0.87 ± 238.0 (`docs/research_sweep_2026-09.md` §1). The 2006 paper's
// table is level 2 (80.6 mm, drag 208.83) and rounds the frequency to 2.0.
const REF_UY_MEAN: f64 = 1.24e-3;
const REF_UY_AMP: f64 = 81.7e-3;
const REF_UY_FREQ: f64 = 1.93;
const REF_UX_MEAN: f64 = -14.87e-3;
const REF_UX_AMP: f64 = 12.73e-3;
const REF_DRAG_MEAN: f64 = 215.18;
const REF_DRAG_AMP: f64 = 77.78;
const REF_LIFT_MEAN: f64 = 0.87;
const REF_LIFT_AMP: f64 = 238.0;
/// The benchmark's reference cycle (FEATFLOW's tables, level 4 — FSI2 at
/// Δt = 0.01: uy 1.24 ± 81.7 mm at 1.93 Hz, ux 14.87 ± 12.73, drag 215.18 ±
/// 77.78, lift 0.87 ± 238.0; FSI3 at Δt = 0.0005: uy 1.45 ± 34.90 at 5.46 Hz,
/// ux 2.86 ± 2.70, drag 460.2 ± 27.47, lift 2.37 ± 153.75;
/// `docs/research_sweep_2026-09.md` §1. The 2006 paper's FSI2 row is level 2
/// (80.6 mm, drag 208.83) with the frequency rounded to 2.0).
struct Refs {
uy_mean: f64,
uy_amp: f64,
uy_freq: f64,
ux_mean: f64,
ux_amp: f64,
drag_mean: f64,
drag_amp: f64,
lift_mean: f64,
lift_amp: f64,
}
fn refs(case: &str) -> Refs {
if case == "FSI3" {
Refs {
uy_mean: 1.45e-3,
uy_amp: 34.90e-3,
uy_freq: 5.46,
ux_mean: -2.86e-3,
ux_amp: 2.70e-3,
drag_mean: 460.2,
drag_amp: 27.47,
lift_mean: 2.37,
lift_amp: 153.75,
}
} else {
Refs {
uy_mean: 1.24e-3,
uy_amp: 81.7e-3,
uy_freq: 1.93,
ux_mean: -14.87e-3,
ux_amp: 12.73e-3,
drag_mean: 215.18,
drag_amp: 77.78,
lift_mean: 0.87,
lift_amp: 238.0,
}
}
}
/// `RTX_FSI2O_AUDIT=dir`: the solver-metric chain on every saved instant
/// under `dir` (`inst_*`, from `RTX_FSI2O_SAVE_EVERY`), no march.
@@ -112,12 +144,27 @@ fn fsi2_on_the_overset() {
trace_steps: 0,
},
);
let case = case_from_env("FSI2O", FSI2);
// `RTX_FSI2O_CASE=FSI3` runs the FSI3 constants (Re 200, ρ_s = ρ_f, E 5.6e6).
let base = if std::env::var("RTX_FSI2O_CASE").as_deref() == Ok("FSI3") {
FSI3
} else {
FSI2
};
let case = case_from_env("FSI2O", base);
let rf = refs(case.name);
let (cname, ruf, rdm, rda, rlm, rla) = (
case.name,
rf.uy_freq,
rf.drag_mean,
rf.drag_amp,
rf.lift_mean,
rf.lift_amp,
);
let r = run_march_overset(case, &config);
let m = &r.result;
let w = m.window(3.0);
println!(
" FSI2 OVERSET (ny = {}, flag {}x2 Quad8, dt = {:.2e}, s = {}, sweeps {}, rounds cap {}, {}): coupled {} steps in {:.0} s wall; {:.1} subit/step (max {}); {} stalled, {} retries (worst residual {:.2e}); conservation {:.2e}; {} wall faces; Newton rescues {:?}; rounds mean {:.2}; reclassified/step {:.2} (fresh {:.2}); patch regenerations {} in {:.0} s; fluid {:.0} s, structure {:.0} s; death {:?}\n measured over [{:.1}, {:.1}] s: uy(A) = {:.3} ± {:.3} mm (ref {:.2} ± {:.1}), ux(A) = {:.3} ± {:.3} mm (ref {:.2} ± {:.2}), f = {:?} Hz (ref {REF_UY_FREQ}); drag {:.2} ± {:.2} (ref {REF_DRAG_MEAN} ± {REF_DRAG_AMP}), lift {:.2} ± {:.2} (ref {REF_LIFT_MEAN} ± {REF_LIFT_AMP}); onset amp {:.3e}{:.3e} m; rigid drag {:.2}",
" {cname} OVERSET (ny = {}, flag {}x2 Quad8, dt = {:.2e}, s = {}, sweeps {}, rounds cap {}, {}): coupled {} steps in {:.0} s wall; {:.1} subit/step (max {}); {} stalled, {} retries (worst residual {:.2e}); conservation {:.2e}; {} wall faces; Newton rescues {:?}; rounds mean {:.2}; reclassified/step {:.2} (fresh {:.2}); patch regenerations {} in {:.0} s; fluid {:.0} s, structure {:.0} s; death {:?}\n measured over [{:.1}, {:.1}] s: uy(A) = {:.3} ± {:.3} mm (ref {:.2} ± {:.1}), ux(A) = {:.3} ± {:.3} mm (ref {:.2} ± {:.2}), f = {:?} Hz (ref {ruf}); drag {:.2} ± {:.2} (ref {rdm} ± {rda}), lift {:.2} ± {:.2} (ref {rlm} ± {rla}); onset amp {:.3e}{:.3e} m; rigid drag {:.2}",
config.ny,
config.flag_nx,
m.dt,
@@ -147,12 +194,12 @@ fn fsi2_on_the_overset() {
config.t_end,
w.uy_mid * 1e3,
w.uy_amp * 1e3,
REF_UY_MEAN * 1e3,
REF_UY_AMP * 1e3,
rf.uy_mean * 1e3,
rf.uy_amp * 1e3,
w.ux_mid * 1e3,
w.ux_amp * 1e3,
REF_UX_MEAN * 1e3,
REF_UX_AMP * 1e3,
rf.ux_mean * 1e3,
rf.ux_amp * 1e3,
w.frequency,
w.drag_mid,
w.drag_amp,