//! P5 (`docs/overset_metal_campaign.md` §5.12): Turek–Hron 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 (Turek–Hron 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); }