P5-1: FSI2 with the fluid on the overset — fsi2_harness/overset.rs (the background without a body, the cylinder–flag patch regenerated around the deformed flag every pass via set_patch_mesh, the wall velocity from the interface velocities along the wetted polygon, the load from the patch's wall faces into WettedSurface::transfer_load — no probes, no clamp, no smoothing), fsi2_harness/overset_march.rs (the harness's rigid phase / release / subiterated coupling with its acceptance rule, no rescue machinery, death returned not panicked), tests/turek_hron_fsi2_overset.rs (RTX_FSI2O_* knobs); rtx-cfd: CurvilinearPisoSolver::wall_tractions (per-face pressure + full-stress traction, surface_force sums the same terms bit-identically); Interface::edges (bottom/tip/top for the generator); cylinder_flag_mms RTX_CF_BEND (P5-0 gate iv: Stokes orders 2.14 / 2.09 on the flag bent to 80 mm)
Documentation / Build API Documentation (push) Canceled after 0s
CI / Build (macos-latest) (push) Canceled after 0s
CI / Build (ubuntu-latest) (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
Documentation / Build User Guide (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (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_0116sg1Qz1gMv9hdcKP1XUam
This commit is contained in:
Omar Sobh
2026-09-07 07:16:53 -07:00
co-authored by Claude Fable 5.1
parent c2451fbacf
commit f0b2563bf8
6 changed files with 1076 additions and 41 deletions
@@ -0,0 +1,97 @@
//! P5 (`docs/overset_metal_campaign.md` §5.12): TurekHron FSI2 with the
//! fluid on the OVERSET — the body-fitted patch following the flag. The
//! structure, coupling and acceptance are the FSI2 harness's; the fluid
//! side is `fsi2_harness::overset`. Defaults are the P5-1 gate run
//! (ny = 41, s = 1, a short march); `RTX_FSI2O_*` knobs as the harness's.
//! Reference (TurekHron FSI2): uy(A) 1.23 ± 80.6 mm at 2.0 Hz, ux(A)
//! 14.58 ± 12.44 mm, drag 208.83 ± 73.75, lift 0.88 ± 234.2.
mod fsi2_harness;
use fsi2_harness::overset_march::{run_march_overset, OversetMarchConfig};
use fsi2_harness::{case_from_env, FSI2};
const REF_UY_AMP: f64 = 80.6e-3;
const REF_UY_FREQ: f64 = 2.0;
const REF_UX_MEAN: f64 = -14.58e-3;
const REF_UX_AMP: f64 = 12.44e-3;
const REF_DRAG_MEAN: f64 = 208.83;
const REF_LIFT_AMP: f64 = 234.2;
#[test]
fn fsi2_on_the_overset() {
let config = OversetMarchConfig::from_env(
"FSI2O",
OversetMarchConfig {
ny: 41,
flag_nx: 35,
t_release: 6.0,
t_end: 7.0,
subcycle: 1,
tol_floor: 2e-4,
rtol: 1e-2,
stall_accept: 5.0,
max_subiterations: 12,
coupler: "aitken".into(),
reuse: 2,
initial_relaxation: 0.5,
c1_interface: false,
predictor: "structure".into(),
sweeps: 100,
max_rounds: 3,
csv_path: None,
trace_steps: 0,
},
);
let case = case_from_env("FSI2O", FSI2);
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 1.23 ± {:.1}), ux(A) = {:.3} ± {:.3} mm (ref {:.2} ± {:.2}), f = {:?} Hz (ref {REF_UY_FREQ}); drag {:.2} ± {:.2} (ref {REF_DRAG_MEAN} ± 73.75), lift {:.2} ± {:.2} (ref 0.88 ± {REF_LIFT_AMP}); onset amp {:.3e}{:.3e} m; rigid drag {:.2}",
config.ny,
config.flag_nx,
m.dt,
config.subcycle,
config.sweeps,
config.max_rounds,
config.coupler,
m.coupled_steps,
m.elapsed,
m.mean_subiterations,
m.max_subiterations,
m.stalled_steps,
m.retried_steps,
m.worst_stall,
m.worst_conservation,
r.faces_used,
m.newton_rescues,
r.rounds_mean,
r.reclassified_mean,
r.fresh_mean,
r.regen_count,
r.regen_seconds,
r.fluid_seconds,
r.structure_seconds,
r.death,
w.t_start,
config.t_end,
w.uy_mid * 1e3,
w.uy_amp * 1e3,
REF_UY_AMP * 1e3,
w.ux_mid * 1e3,
w.ux_amp * 1e3,
REF_UX_MEAN * 1e3,
REF_UX_AMP * 1e3,
w.frequency,
w.drag_mid,
w.drag_amp,
w.lift_mid,
w.lift_amp,
w.amp_early,
w.amp_late,
m.rigid_drag
);
assert!(m.final_state_finite, "the flag's state is not finite");
assert!(r.death.is_none(), "the coupling died: {:?}", r.death);
}