rtx-fsi: time-resolved-honest load record — per-step sampling, interval median
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
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
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
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
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
The reported drag/lift were one instantaneous measure_force sample every 10th coupled step, and the embedded-boundary surface force carries zero-mean sign-flipping fresh-cell pressure transients at step scale (measured: +-4,000-scale swings against a +-78 reference while displacements matched the benchmark to 0.1%, and the window MEDIANS sat near-physical). The record now samples the committed field every step and records the interval median — the estimator the CSV analysis supports; ten steps span 2-5% of a flap period, so nothing physical is smeared. Reporting only: measure_force reads the committed state. Verified on both committed defaults against pre-change logs — every displacement, conservation, and coupling digit identical; only the load lines moved, and toward the benchmark: FSI3 drag 628.66 +- 545.11 -> 443.26 +- 148.50 (ref 460.2 +- 27.47, mid now within 3.7%), lift amp 2289 -> 668; FSI2 lift amp 52 -> 28. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01X2GmJXeQ2njUecEKiJZ1G2
This commit is contained in:
co-authored by
Claude Fable 5
parent
bff84ccdcc
commit
137a62c4ea
@@ -16,7 +16,7 @@ use rtx_fea::materials::{LinearElastic, MaterialDatabase};
|
||||
use rtx_fea::mesh::{MaterialId, NodeId};
|
||||
use rtx_fsi::{IqnIls, Subiterated};
|
||||
|
||||
use super::{BenchmarkCase, Fsi2Harness, clamp_left, crossing_frequency, env_or, mid_amp};
|
||||
use super::{BenchmarkCase, Fsi2Harness, clamp_left, crossing_frequency, env_or, median, mid_amp};
|
||||
|
||||
/// Everything a march run is parameterised by. `from_env` reads the
|
||||
/// `RTX_<PREFIX>_*` knobs over a set of defaults.
|
||||
@@ -372,6 +372,19 @@ pub fn run_march(case: BenchmarkCase, config: &MarchConfig) -> MarchResult {
|
||||
let mut force_times: Vec<f64> = Vec::new();
|
||||
let mut drag_series: Vec<f64> = Vec::new();
|
||||
let mut lift_series: Vec<f64> = Vec::new();
|
||||
// Per-step load samples for the current recording interval. The
|
||||
// recorded value is the interval MEDIAN, not one instantaneous
|
||||
// sample: the embedded-boundary surface force carries zero-mean
|
||||
// sign-flipping fresh-cell pressure transients at step scale
|
||||
// (measured on the FSI2 s = 1 benchmark run: +-4,000-scale
|
||||
// instantaneous swings against a +-78 reference while the window
|
||||
// MEDIANS sat near-physical — drag 187 vs ref 215). The median
|
||||
// rejects the transient outliers; ten coupled steps span 2-5% of a
|
||||
// flap period, so nothing physical is smeared. Reporting only —
|
||||
// measure_force reads the committed state and cannot perturb the
|
||||
// trajectory.
|
||||
let mut interval_drag: Vec<f64> = Vec::new();
|
||||
let mut interval_lift: Vec<f64> = Vec::new();
|
||||
let mut csv = csv_path
|
||||
.as_ref()
|
||||
.map(|p| std::fs::File::create(p).expect("csv path"));
|
||||
@@ -554,8 +567,14 @@ pub fn run_march(case: BenchmarkCase, config: &MarchConfig) -> MarchResult {
|
||||
times.push(t);
|
||||
ux_series.push(ux);
|
||||
uy_series.push(uy);
|
||||
let (drag_now, lift_now) = harness.measure_force(&solver.borrow(), &field.borrow());
|
||||
interval_drag.push(drag_now);
|
||||
interval_lift.push(lift_now);
|
||||
if (step + 1) % 10 == 0 {
|
||||
let (drag, lift) = harness.measure_force(&solver.borrow(), &field.borrow());
|
||||
let drag = median(&mut interval_drag);
|
||||
let lift = median(&mut interval_lift);
|
||||
interval_drag.clear();
|
||||
interval_lift.clear();
|
||||
force_times.push(t);
|
||||
drag_series.push(drag);
|
||||
lift_series.push(lift);
|
||||
|
||||
@@ -284,6 +284,20 @@ pub fn mid_amp(series: &[f64]) -> (f64, f64) {
|
||||
(0.5 * (max + min), 0.5 * (max - min))
|
||||
}
|
||||
|
||||
/// Median of a sample buffer (sorts in place; empty buffers read 0).
|
||||
pub fn median(samples: &mut [f64]) -> f64 {
|
||||
if samples.is_empty() {
|
||||
return 0.0;
|
||||
}
|
||||
samples.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
let n = samples.len();
|
||||
if n % 2 == 1 {
|
||||
samples[n / 2]
|
||||
} else {
|
||||
0.5 * (samples[n / 2 - 1] + samples[n / 2])
|
||||
}
|
||||
}
|
||||
|
||||
/// Frequency from linearly interpolated upward crossings of the mean.
|
||||
pub fn crossing_frequency(times: &[f64], series: &[f64]) -> Option<f64> {
|
||||
let (mean, _) = mid_amp(series);
|
||||
|
||||
Reference in New Issue
Block a user