CI / Test (macos-latest) (push) Blocked by required conditions
CI / Test (ubuntu-latest) (push) Blocked by required conditions
CI / Python Bindings (maturin) (macos-latest) (push) Blocked by required conditions
CI / Build (macos-latest) (push) Waiting to run
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
Documentation / Build API Documentation (push) Failing after 4s
CI / Build CPU-Only (Explicit) (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 5s
CI / Format Check (push) Failing after 13s
CI / Clippy Check (push) Failing after 45s
CI / Build (ubuntu-latest) (push) Failing after 2m1s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m35s
Co-Authored-By: Claude Fable 5.1 <[email protected]>
76 lines
2.9 KiB
Rust
76 lines
2.9 KiB
Rust
//! S2-3 pre-flight (host): the flag + cylinder body at ny 62 — the mask
|
|
//! builds, its cut geometry closes, the counts and the build time (the
|
|
//! moving body's per-step host rebuild cost) are recorded.
|
|
use rtx_cfd::solvers::incompressible::embedded3::{Body, Boundaries, Grid, Mask, Side};
|
|
|
|
const H: f64 = 0.41;
|
|
const FLAG_X0: f64 = 0.6;
|
|
const FLAG_LEN: f64 = 0.35;
|
|
const FLAG_HALF: f64 = 0.01;
|
|
const FLAG_SPAN: f64 = 0.2;
|
|
const AMP: f64 = 0.084;
|
|
const BETA_L: f64 = 1.875_104_069;
|
|
|
|
fn mode(s: f64) -> f64 {
|
|
let b = BETA_L;
|
|
let sigma = (b.sinh() - b.sin()) / (b.cosh() + b.cos());
|
|
let phi = |s: f64| (b * s).cosh() - (b * s).cos() - sigma * ((b * s).sinh() - (b * s).sin());
|
|
phi(s) / phi(1.0)
|
|
}
|
|
|
|
fn flag_2d(x: f64, y: f64, phase: f64) -> f64 {
|
|
let n = 40;
|
|
let mut best = f64::INFINITY;
|
|
let point = |m: usize| {
|
|
let s = m as f64 / n as f64;
|
|
(FLAG_X0 + s * FLAG_LEN, 0.2 + AMP * mode(s) * phase)
|
|
};
|
|
for m in 0..n {
|
|
let (ax, ay) = point(m);
|
|
let (bx, by) = point(m + 1);
|
|
let (ex, ey) = (bx - ax, by - ay);
|
|
let u = (((x - ax) * ex + (y - ay) * ey) / (ex * ex + ey * ey)).clamp(0.0, 1.0);
|
|
let d = ((x - ax - u * ex).powi(2) + (y - ay - u * ey).powi(2)).sqrt();
|
|
best = best.min(d);
|
|
}
|
|
best - FLAG_HALF
|
|
}
|
|
|
|
fn flag_3d(x: f64, y: f64, z: f64, phase: f64, r: f64) -> f64 {
|
|
let d2 = flag_2d(x, y, phase);
|
|
let q1 = d2 + r;
|
|
let q2 = (z - 0.5 * H).abs() - 0.5 * FLAG_SPAN + r;
|
|
(q1.max(0.0).powi(2) + q2.max(0.0).powi(2)).sqrt() + q1.max(q2).min(0.0) - r
|
|
}
|
|
|
|
#[test]
|
|
fn flag_body_builds_at_ny_62() {
|
|
let ny = 62;
|
|
let h = H / ny as f64;
|
|
let nx = (2.5 / h).round() as usize;
|
|
let g = Grid::cubic(nx, ny, ny, h);
|
|
let cyl = |x: f64, y: f64| ((x - 0.2_f64).powi(2) + (y - 0.2_f64).powi(2)).sqrt() - 0.05;
|
|
for phase in [0.0, 1.0] {
|
|
let body = Body::from_sdf(move |x, y, z, _t| cyl(x, y).min(flag_3d(x, y, z, phase, h)));
|
|
let b = Boundaries {
|
|
x1: Side::PressureOutlet,
|
|
..Boundaries::default()
|
|
};
|
|
let start = std::time::Instant::now();
|
|
let mask = Mask::build_cut(&body, g, 0.0, b).expect("mask");
|
|
let build = start.elapsed().as_secs_f64();
|
|
let cut = mask.cut().unwrap();
|
|
let (area, closure) = cut.wall_area_and_closure();
|
|
let solid = g.cells() - mask.fluid_cells();
|
|
println!(
|
|
" phase {phase}: {} cells, {} fluid, {solid} solid, {} merged; wall area {area:.4} m² (cylinder 0.129 + flag ~0.156), closure {:.2e}; build {build:.2} s",
|
|
g.cells(),
|
|
mask.fluid_cells(),
|
|
mask.merged_cells(),
|
|
(closure[0].powi(2) + closure[1].powi(2) + closure[2].powi(2)).sqrt()
|
|
);
|
|
assert!(solid > 1000 && mask.fluid_cells() > g.cells() / 2);
|
|
assert!((closure[0].powi(2) + closure[1].powi(2) + closure[2].powi(2)).sqrt() < 1e-9);
|
|
}
|
|
}
|