Merge r8e-coupled-dt-stability (R8-e: the coupled 3D FSI dt instability = the harness's structure-to-fluid mapping, fix RTX_E3FSI_KIN=surface; default-off). Merge fixes with R8-h: the surface station list over stations() (the flat tip's station A = the mean of the tip corners); the impulse test's capsule-only flat_tip(). Merged-tree gate (r6/merge_gate7): slab default / check / all-host / plate byte-identical to main's base, suites 2/2 3/3, the default coupled smoke = R8-a's march row for row, a KIN=surface + TIP=flat + LOADS_DEVICE coupled run clean
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (ubuntu-latest) (push) Blocked by required conditions
CI / WASM Build + Size Check (push) Blocked by required conditions
CI / Distributed Training Tests (push) Blocked by required conditions
CI / CI Success (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
CI / Format Check (push) Failing after 4s
CI / Build CPU-Only (Explicit) (push) Failing after 4s
Performance Benchmarks / Run Benchmarks (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 6s
CI / Build (ubuntu-latest) (push) Failing after 11s
CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Clippy Check (push) Failing after 4s
Documentation / Build API Documentation (push) Failing after 20s

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-26 05:02:51 -05:00
co-authored by Claude Opus 5.5
2 changed files with 275 additions and 1 deletions
@@ -18,7 +18,11 @@
//! `RTOL` (1e-3), `FLOOR` (1.5e-7 on the centreline vector), `MAX_SUBIT`
//! (12), `STALL_ACCEPT` (5), `GAMMA` (0.7), `SPEED` (3.0 m/s, the band's
//! surface-speed bound), `CSV` (per-step series), `TRACE` (steps whose
//! passes are printed).
//! passes are printed); R8-e: `KIN` (`centre` = the mid-plane nodes drive
//! the fluid's centreline; `surface` = the mean of the bottom and top edge
//! nodes, the nodes the loads land on — the transfer-consistent pair that
//! removes the small-dt instability), `LINE_CSV` (the committed centreline
//! and the per-station mid/bottom/top y displacement per step).
//!
//! `RTX_E3FSI_NY=62 RTX_E3FSI_CSV=<path> RTX_CUDA_ARCH=sm_120 cargo test --release -p rtx-fsi \
//! --features cuda --test fsi2_embedded3 -- --ignored --nocapture`
@@ -88,6 +92,9 @@ struct Flag {
/// (reference y, wetted index), ascending (corners included).
tip: Vec<(f64, usize)>,
a_node: NodeId,
/// R8-e: the bottom and top edge nodes at each station's x (the wetted
/// surface the loads land on).
surface: Vec<[NodeId; 2]>,
}
impl Flag {
@@ -128,6 +135,13 @@ impl Flag {
top,
tip,
a_node: find(0.6, 0.2),
// Over stations(): with the flat tip, station A (x 0.60) takes the mean of the tip's two corner nodes (merge of R8-e with R8-h).
surface: (0..stations())
.map(|k| {
let x = X0 + 0.01 * k as f64;
[find(x, 0.19), find(x, 0.21)]
})
.collect(),
}
}
}
@@ -308,6 +322,11 @@ fn fsi2_on_embedded3() {
.unwrap();
f
});
// R8-e `RTX_E3FSI_LINE_CSV`: the committed centreline per coupled step
// (t, then x, y displacement per station) — the unstable mode's shape.
let mut line_csv = std::env::var("RTX_E3FSI_LINE_CSV")
.ok()
.map(|p| std::fs::File::create(p).expect("line csv"));
let start = std::time::Instant::now();
// Phase 1: the rigid flag (target 1: the rest state vs CFD2 136.7 / 10.53).
@@ -401,8 +420,27 @@ fn fsi2_on_embedded3() {
})
.collect();
let a_dofs = flag.borrow().node_dofs(flag_geo.a_node);
// R8-e `RTX_E3FSI_KIN=surface`: the fluid's centreline is the mean of the
// bottom and top edge nodes at each station (the nodes the loads land on)
// instead of the mid-plane nodes (default `centre`).
let kin_surface = std::env::var("RTX_E3FSI_KIN").is_ok_and(|v| v == "surface");
let surface_dofs: Vec<[usize; 4]> = flag_geo
.surface
.iter()
.map(|[b, t]| {
let (db, dt_) = (flag.borrow().node_dofs(*b), flag.borrow().node_dofs(*t));
[db[0], db[1], dt_[0], dt_[1]]
})
.collect();
let extract = |s: &DynamicState| -> Vec<f64> {
let mut c = vec![0.0; 2 * stations()];
if kin_surface {
for (k, d) in surface_dofs.iter().enumerate() {
c[2 * k] = 0.5 * (s.displacement[d[0]] + s.displacement[d[2]]);
c[2 * k + 1] = 0.5 * (s.displacement[d[1]] + s.displacement[d[3]]);
}
return c;
}
for (k, d) in centre_dofs.iter().enumerate() {
c[2 * k] = s.displacement[d[0]];
c[2 * k + 1] = s.displacement[d[1]];
@@ -624,6 +662,16 @@ fn fsi2_on_embedded3() {
)
.unwrap();
}
if let Some(f) = line_csv.as_mut() {
// Then the y displacement of the mid-plane, bottom and top nodes per station.
let mut c: Vec<String> = c_fluid_n.iter().map(|v| format!("{v:.6e}")).collect();
for (k, d) in surface_dofs.iter().enumerate() {
let yc = flag_state.displacement[centre_dofs[k][1]];
let (yb, yt) = (flag_state.displacement[d[1]], flag_state.displacement[d[3]]);
c.extend([yc, yb, yt].map(|v| format!("{v:.6e}")));
}
writeln!(f, "{t_new:.6},{}", c.join(",")).unwrap();
}
let at_end = step + 1 == coupled_steps;
if let Some(dir) = save_dir
.as_ref()