embedded3 flag wake: RTX_E3_FLAG_HEIGHT — the duct's y extent as a knob (default H; the cell size stays H/ny), the body re-centred (body_cy); the inflow paraboloid and the 2D branch follow it; unset-knob slab gate byte-identical
CI / Test (macos-latest) (push) Blocked by required conditions
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
Performance Benchmarks / Run Benchmarks (push) Failing after 4s
Documentation / Build API Documentation (push) Failing after 3s
CI / Format Check (push) Failing after 25s
CI / Clippy Check (push) Failing after 25s
CI / Build CPU-Only (Explicit) (push) Failing after 1m23s
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Build (ubuntu-latest) (push) Failing after 4s
Documentation / Build User Guide (push) Successful in 20s

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Omar Sobh
2026-09-23 09:26:34 -05:00
co-authored by Claude Fable 5.1
parent e562bf8663
commit b848d98719
@@ -1,6 +1,8 @@
//! embedded3 S2-3: the free-ended flag with prescribed motion — the first //! embedded3 S2-3: the free-ended flag with prescribed motion — the first
//! honest 3D wake. The TurekHron channel (2.5 × 0.41) extruded to depth //! honest 3D wake. The TurekHron channel (2.5 × 0.41) extruded to depth
//! 0.41 with the cylinder (D 0.1 at (0.2, 0.2)) across the width, the flag //! 0.41 with the cylinder (D 0.1 at (0.2, 0.2)) across the width, the flag
//! (`RTX_E3_FLAG_HEIGHT` / `RTX_E3_FLAG_DEPTH` grow the duct around the
//! unchanged body, re-centred: the 2026-09-22/23 explorations), the flag
//! 0.35 × 0.02 × 0.2 centred in z (z 0.1050.305), its centreline deflected //! 0.35 × 0.02 × 0.2 centred in z (z 0.1050.305), its centreline deflected
//! as the first clamped-free beam mode with the 2D FSI2 flat-tip record's //! as the first clamped-free beam mode with the 2D FSI2 flat-tip record's
//! tip amplitude 84 mm at 1.930 Hz (motion prescribed, no structure), the //! tip amplitude 84 mm at 1.930 Hz (motion prescribed, no structure), the
@@ -139,7 +141,7 @@ fn flag_2d_recorded(rec: &Recorded, x: f64, y: f64, t: f64) -> (f64, (f64, f64))
POLY.with(|cell| { POLY.with(|cell| {
let mut c = cell.borrow_mut(); let mut c = cell.borrow_mut();
if c.0.to_bits() != t.to_bits() { if c.0.to_bits() != t.to_bits() {
c.1 = rec.at(t, CY); c.1 = rec.at(t, body_cy());
inset_last(&mut c.1, tip_inset()); inset_last(&mut c.1, tip_inset());
c.0 = t; c.0 = t;
} }
@@ -179,7 +181,7 @@ fn flag_2d_analytic(x: f64, y: f64, t: f64) -> (f64, f64) {
for (m, p) in c.1.iter_mut().enumerate() { for (m, p) in c.1.iter_mut().enumerate() {
let s = m as f64 / N as f64; let s = m as f64 / N as f64;
let (d, v) = deflection(s, t); let (d, v) = deflection(s, t);
*p = (FLAG_X0 + s * FLAG_LEN, CY + d, v); *p = (FLAG_X0 + s * FLAG_LEN, body_cy() + d, v);
} }
let inset = tip_inset(); let inset = tip_inset();
if inset > 0.0 { if inset > 0.0 {
@@ -226,6 +228,19 @@ fn duct_depth() -> f64 {
env_f("RTX_E3_FLAG_DEPTH", H) env_f("RTX_E3_FLAG_DEPTH", H)
} }
/// The duct's height (the y extent): `RTX_E3_FLAG_HEIGHT` (default H).
/// The cell size stays `H / ny` (the benchmark's rung definition); the
/// body is re-centred in the taller duct (2026-09-23, the "big duct").
fn duct_height() -> f64 {
env_f("RTX_E3_FLAG_HEIGHT", H)
}
/// The cylinder's centre and the flag's rest centreline: `CY` in the
/// benchmark duct, lifted by half the added height otherwise.
fn body_cy() -> f64 {
CY + 0.5 * (duct_height() - H)
}
/// The flag in 3D: the extruded capsule cut to the span with edges /// The flag in 3D: the extruded capsule cut to the span with edges
/// rounded to radius `r` (no cut at the full width). /// rounded to radius `r` (no cut at the full width).
fn flag_3d(x: f64, y: f64, z: f64, t: f64, r: f64) -> (f64, (f64, f64)) { fn flag_3d(x: f64, y: f64, z: f64, t: f64, r: f64) -> (f64, (f64, f64)) {
@@ -242,8 +257,8 @@ fn flag_3d(x: f64, y: f64, z: f64, t: f64, r: f64) -> (f64, (f64, f64)) {
} }
fn inflow(y: f64, z: f64) -> f64 { fn inflow(y: f64, z: f64) -> f64 {
let d = duct_depth(); let (hd, d) = (duct_height(), duct_depth());
16.0 * U_M * y * z * (H - y) * (d - z) / (H * H * d * d) 16.0 * U_M * y * z * (hd - y) * (d - z) / (hd * hd * d * d)
} }
#[test] #[test]
@@ -253,6 +268,8 @@ fn flag_wake_on_the_device() {
let periods = env_f("RTX_E3_FLAG_PERIODS", 2.0); let periods = env_f("RTX_E3_FLAG_PERIODS", 2.0);
let h = H / ny as f64; let h = H / ny as f64;
let nx = (L / h).round() as usize; let nx = (L / h).round() as usize;
// The grid's rows: the benchmark's `ny` unless the duct is taller.
let ny_grid = (duct_height() / h).round() as usize;
// `RTX_E3_FLAG_NZ=4`: a thin slab periodic in z with the 2D inflow (Ū = 1) — the // `RTX_E3_FLAG_NZ=4`: a thin slab periodic in z with the 2D inflow (Ū = 1) — the
// flag as a 2D problem, minutes per rung: the instrument for the load routes' parts. // flag as a 2D problem, minutes per rung: the instrument for the load routes' parts.
let slab_nz = env_f("RTX_E3_FLAG_NZ", 0.0) as usize; let slab_nz = env_f("RTX_E3_FLAG_NZ", 0.0) as usize;
@@ -321,7 +338,8 @@ fn flag_wake_on_the_device() {
); );
let inflow_at = move |y: f64, z: f64| { let inflow_at = move |y: f64, z: f64| {
if slab_nz > 0 || inflow_2d { if slab_nz > 0 || inflow_2d {
6.0 * y * (H - y) / (H * H) let hd = duct_height();
6.0 * y * (hd - y) / (hd * hd)
} else { } else {
inflow(y, z) inflow(y, z)
} }
@@ -333,7 +351,8 @@ fn flag_wake_on_the_device() {
(0.0, 0.0, 0.0) (0.0, 0.0, 0.0)
} }
}); });
let cyl = move |x: f64, y: f64| ((x - CX).powi(2) + (y - CY).powi(2)).sqrt() - R_CYL; let cy = body_cy();
let cyl = move |x: f64, y: f64| ((x - CX).powi(2) + (y - cy).powi(2)).sqrt() - R_CYL;
let r_fillet = root_fillet(); let r_fillet = root_fillet();
let body = Body::from_sdf(move |x, y, z, t| { let body = Body::from_sdf(move |x, y, z, t| {
fillet_union(cyl(x, y), flag_3d(x, y, z, t, r_edge).0, r_fillet) fillet_union(cyl(x, y), flag_3d(x, y, z, t, r_edge).0, r_fillet)
@@ -347,10 +366,10 @@ fn flag_wake_on_the_device() {
} }
}); });
solver.set_moving_body(body); solver.set_moving_body(body);
let g = Grid::cubic(nx, ny, nz, h); let g = Grid::cubic(nx, ny_grid, nz, h);
let mut field = Field::new(g); let mut field = Field::new(g);
for k in 0..nz { for k in 0..nz {
for j in 0..ny { for j in 0..ny_grid {
let u0 = inflow_at((j as f64 + 0.5) * h, (k as f64 + 0.5) * h); let u0 = inflow_at((j as f64 + 0.5) * h, (k as f64 + 0.5) * h);
for i in 0..=nx { for i in 0..=nx {
field.u[g.uface(k, j, i)] = u0; field.u[g.uface(k, j, i)] = u0;
@@ -359,8 +378,10 @@ fn flag_wake_on_the_device() {
} }
solver.initialize(&mut field); solver.initialize(&mut field);
println!( println!(
" flag wake ny {ny} (span {}; inflow {}, z sides {}; root fillet {:.4} m, tip inset {:.4} m): {nx}×{ny}×{nz} = {} cells, h {h:.4e}, dt {dt:.3e}, {periods} periods = {t_end:.3} s, {} steps", " flag wake ny {ny} (span {}; duct {:.2} × {:.2} m, inflow {}, z sides {}; root fillet {:.4} m, tip inset {:.4} m): {nx}×{ny_grid}×{nz} = {} cells, h {h:.4e}, dt {dt:.3e}, {periods} periods = {t_end:.3} s, {} steps",
flag_span(), flag_span(),
duct_height(),
duct_depth(),
if slab_nz > 0 || inflow_2d { "2d" } else { "3d" }, if slab_nz > 0 || inflow_2d { "2d" } else { "3d" },
if slab_nz > 0 { if slab_nz > 0 {
"periodic" "periodic"
@@ -443,7 +464,7 @@ fn flag_wake_on_the_device() {
// recorded mode (until 2026-09-21 this column held the analytic // recorded mode (until 2026-09-21 this column held the analytic
// first mode even then — R2's fits use the record directly). // first mode even then — R2's fits use the record directly).
let tip = match recorded() { let tip = match recorded() {
Some(rec) => rec.at(t, CY).last().map_or(0.0, |p| p.1 - CY), Some(rec) => rec.at(t, body_cy()).last().map_or(0.0, |p| p.1 - body_cy()),
None => deflection(1.0, t).0, None => deflection(1.0, t).0,
}; };
if sample { if sample {