rtx-cfd: the deformed cylinder–flag build's hull source carries the deformed outline — the cylinder + tip disc alone give the chord under a bent flag's convex side (P5-2 died at tip −35 mm with the patch 4.4 h thick where 6 h was asked, an acceptor's donor on a prescribed face); the death reproduced from the last saved instant by extrapolating the interface (fsi2_overset_probe_death_from_instant, with the failing acceptor's ray geometry and the overlap depths that build) and gone with the fix at every τ; RTX_FSI2O_ROWS; the zero-displacement mesh gate at 1e-5 (the pipeline's), the outline gate 1e-12 unchanged
CI / Build (macos-latest) (push) Failing after 18s
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 API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (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
CI / Build (macos-latest) (push) Failing after 18s
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 API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
CI / Python Bindings (maturin) (macos-latest) (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (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:
co-authored by
Claude Fable 5.1
parent
3c2add3f32
commit
06229dd9a2
@@ -134,3 +134,158 @@ fn fsi2_on_the_overset() {
|
||||
assert!(m.final_state_finite, "the flag's state is not finite");
|
||||
assert!(r.death.is_none(), "the coupling died: {:?}", r.death);
|
||||
}
|
||||
|
||||
/// `RTX_FSI2O_PROBE_INSTANT=dir`: the P5-2 warm replica died at t = 10.99
|
||||
/// s (tip −35 mm) with "acceptor p donor cell not active". From the
|
||||
/// instant, extrapolate the interface along its velocity and find where
|
||||
/// the overlap first refuses — with the warm chain from the instant's
|
||||
/// mesh and with cold builds — reporting the acceptor, its donor cell's
|
||||
/// class, and the patch's thickness there.
|
||||
#[test]
|
||||
fn fsi2_overset_probe_death_from_instant() {
|
||||
use rtx_cfd::mesh::patch_gen::{
|
||||
cylinder_flag_patch_deformed, cylinder_flag_patch_deformed_from,
|
||||
};
|
||||
use rtx_cfd::solvers::incompressible::{CellClass, OverlapMap};
|
||||
let Ok(dir) = std::env::var("RTX_FSI2O_PROBE_INSTANT") else {
|
||||
return;
|
||||
};
|
||||
let dir = std::path::Path::new(&dir);
|
||||
let case = case_from_env("FSI2O", FSI2);
|
||||
let (fluid, d, t) =
|
||||
fsi2_harness::overset::OversetFluid::from_instant(case, 41, 35, dir).expect("instant");
|
||||
let dd: Vec<f64> = {
|
||||
let bytes = std::fs::read(dir.join("patch_dd.bin")).expect("dd");
|
||||
bytes
|
||||
.chunks_exact(8)
|
||||
.map(|c| f64::from_le_bytes(c.try_into().unwrap()))
|
||||
.collect()
|
||||
};
|
||||
let h = fluid.h;
|
||||
let nx = fluid.nx;
|
||||
let tip_y = d[2 * fluid.interface.tip[fluid.interface.tip.len() / 2] + 1];
|
||||
println!(
|
||||
" instant t = {t:.4}: tip uy {tip_y:+.4} m, hole {} fringe {} acceptors {}",
|
||||
fluid.solver.overlap().hole_cells(),
|
||||
fluid.solver.overlap().fringe_count(),
|
||||
fluid.solver.overlap().acceptors.len()
|
||||
);
|
||||
let mut warm_prev = fluid.solver.patch().mesh().clone();
|
||||
for k in 0..=12 {
|
||||
let tau = 0.005 * k as f64;
|
||||
let dk: Vec<f64> = d.iter().zip(&dd).map(|(a, v)| a + v * tau).collect();
|
||||
let edges = fluid.interface.edges(&dk);
|
||||
let fillet = 0.5 * 0.41 / 41.0;
|
||||
let cold = cylinder_flag_patch_deformed(
|
||||
[0.2, 0.2],
|
||||
0.05,
|
||||
0.01,
|
||||
&edges,
|
||||
0.6,
|
||||
h,
|
||||
fillet,
|
||||
6.0 * h,
|
||||
12,
|
||||
4.0,
|
||||
100,
|
||||
)
|
||||
.expect("cold");
|
||||
let warm = cylinder_flag_patch_deformed_from(
|
||||
Some(&warm_prev),
|
||||
[0.2, 0.2],
|
||||
0.05,
|
||||
0.01,
|
||||
&edges,
|
||||
0.6,
|
||||
h,
|
||||
fillet,
|
||||
6.0 * h,
|
||||
12,
|
||||
4.0,
|
||||
20,
|
||||
)
|
||||
.expect("warm");
|
||||
let tip_now = dk[2 * fluid.interface.tip[fluid.interface.tip.len() / 2] + 1];
|
||||
for (name, mesh) in [("cold", &cold.0), ("warm", &warm.0)] {
|
||||
let valid = mesh.validate(80.0).err();
|
||||
let r = OverlapMap::build(mesh, nx, 41, h, h, 4);
|
||||
match r {
|
||||
Ok(map) => println!(
|
||||
" τ = {tau:.3} tip {tip_now:+.4}: {name} valid {:?}, overlap ok (hole {} fringe {})",
|
||||
valid.is_none(),
|
||||
map.hole_cells(),
|
||||
map.fringe_count()
|
||||
),
|
||||
Err(e) => {
|
||||
let msg = format!("{e:?}");
|
||||
// The failing acceptor's geometry, and the overlap depth
|
||||
// that would build.
|
||||
let mut extra = String::new();
|
||||
if let Some(a0) = msg.find("acceptor ") {
|
||||
let k: usize = msg[a0 + 9..]
|
||||
.split(' ')
|
||||
.next()
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap();
|
||||
let c = mesh.cell(mesh.nn() - 1, k);
|
||||
let ac = mesh.centre(c);
|
||||
let inner = mesh.node_xy(mesh.node(0, k));
|
||||
let outer = mesh.node_xy(mesh.node(mesh.nn(), k));
|
||||
let r8 = mesh.node_xy(mesh.node(8, k));
|
||||
let thick =
|
||||
((outer[0] - inner[0]).powi(2) + (outer[1] - inner[1]).powi(2)).sqrt();
|
||||
let hole_depth =
|
||||
((r8[0] - inner[0]).powi(2) + (r8[1] - inner[1]).powi(2)).sqrt();
|
||||
let mut rows_ok = Vec::new();
|
||||
for rows in [5usize, 6, 7, 8] {
|
||||
if OverlapMap::build(mesh, nx, 41, h, h, rows).is_ok() {
|
||||
rows_ok.push(rows);
|
||||
}
|
||||
}
|
||||
extra = format!(
|
||||
" — acceptor {k} centre ({:.3}, {:.3}); its ray: wall node ({:.3}, {:.3}), outer ({:.3}, {:.3}), thickness {:.2} h, hole depth {:.2} h, band {:.2} h; overlap_rows that build: {rows_ok:?}",
|
||||
ac[0], ac[1], inner[0], inner[1], outer[0], outer[1], thick / h, hole_depth / h, (thick - hole_depth) / h
|
||||
);
|
||||
}
|
||||
if let Some(i0) = msg.find("cell (") {
|
||||
let coords: Vec<usize> = msg[i0 + 6..]
|
||||
.split(')')
|
||||
.next()
|
||||
.unwrap()
|
||||
.split(',')
|
||||
.map(|s| s.trim().parse().unwrap())
|
||||
.collect();
|
||||
let (j, i) = (coords[0], coords[1]);
|
||||
let (x, y) = ((i as f64 + 0.5) * h, (j as f64 + 0.5) * h);
|
||||
// The nearest inner-ring node and the patch thickness along its ray.
|
||||
let mut best = (f64::INFINITY, 0usize);
|
||||
for s in 0..=mesh.ns() {
|
||||
let p = mesh.node_xy(mesh.node(0, s));
|
||||
let dd2 = (p[0] - x).powi(2) + (p[1] - y).powi(2);
|
||||
if dd2 < best.0 {
|
||||
best = (dd2, s);
|
||||
}
|
||||
}
|
||||
let s = best.1;
|
||||
let inner = mesh.node_xy(mesh.node(0, s));
|
||||
let outer = mesh.node_xy(mesh.node(mesh.nn(), s));
|
||||
let r8 = mesh.node_xy(mesh.node(8, s));
|
||||
let thick = ((outer[0] - inner[0]).powi(2) + (outer[1] - inner[1]).powi(2)).sqrt();
|
||||
let hole_depth = ((r8[0] - inner[0]).powi(2) + (r8[1] - inner[1]).powi(2)).sqrt();
|
||||
extra += &format!(
|
||||
" — cell ({j}, {i}) at ({x:.3}, {y:.3}); nearest wall node s = {s} at ({:.3}, {:.3}); ray thickness {:.3} h, hole depth (row 8) {:.3} h, overlap band {:.3} h; outer node ({:.3}, {:.3})",
|
||||
inner[0], inner[1], thick / h, hole_depth / h, (thick - hole_depth) / h, outer[0], outer[1]
|
||||
);
|
||||
let _ = CellClass::Hole;
|
||||
}
|
||||
println!(
|
||||
" τ = {tau:.3} tip {tip_now:+.4}: {name} valid {:?}, overlap REFUSED: {msg}{extra}",
|
||||
valid.is_none()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
warm_prev = warm.0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user