rtx-cfd: indexed polygon SDF — bit-identical queries, the fluid's measured hot function cut
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
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (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
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
The 2026-08-30 fluid profile (symbolized samples, rigid AND coupled phases of the FSI3 default) attributed the fluid step to the function: polygon_signed_distance 51% rigid / 35% coupled — the embedded mask rebuild and its ghost reconstruction walk every edge of the ~150-vertex interface polygon for every cell-centre and face query, every step. (Also measured, refuting the parked consolidation: Level::new — the MG hierarchy build — is 0.5-0.7% in BOTH phases; caching it would buy nothing. The MG smoother at 34-40% is the honest remaining fluid cost.) PolygonSdf (solvers/incompressible/polygon_sdf.rs): a binned edge index whose query is BIT-IDENTICAL to polygon_signed_distance by construction — per-edge distances use the same float ops, the ring search provably visits a superset of the argmin (convex-projection lower bound sqrt(d_out^2 + ((r-1)b)^2)), and parity XORs the same ray tests over exactly the straddling edges (y-binned). Equality is ASSERTED, not assumed: tests compare to_bits against the brute force over ~40k adversarial points (flag-like walks, random polygons with degenerate zero-length edges, horizontal-edge/vertex-y rays). Wired into EmbeddedBody::polygon and the FSI harness's shared geometry (rebuilt per set_geometry, ~microseconds for 150 edges). Verification — the bar for a bit-exact change is digit identity, and it holds: FSI2 and FSI3 committed defaults reproduce EVERY printed digit of the banded-LU baseline logs (uy 3.7732±3.7920 / 6.0229± 25.2190 mm, conservation 8.26e-12 / 1.49e-12, rigid drags 121.4 / 426.9); rtx-cfd full suite 0 failures; rtx-fsi lib/piston/transfer/ FSI1 green. The study pins need no re-run: the trajectories are unchanged by construction and confirmed by measurement. Wall clock: FSI2 rigid 323 -> 167 s (1.93x), whole default 400 -> 225 s; FSI3 rigid 420 -> 250 s (1.68x), whole default 539 -> 343 s. Cumulative with the banded LU this session: FSI3 default 944 -> 343 s (2.75x), FSI2 524 -> 225 s (2.33x). 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
0b4f306ed1
commit
6c48e53998
@@ -19,7 +19,7 @@ use nalgebra::Vector3;
|
||||
use rtx_cfd::CfdConfig;
|
||||
use rtx_cfd::solvers::incompressible::{
|
||||
AleBoundaries, ConvectionScheme, EmbeddedBody, EmbeddedParameters, EmbeddedPisoSolver,
|
||||
FlowField, PoissonSolverKind, SideBoundary, polygon_interface_velocity,
|
||||
FlowField, PoissonSolverKind, PolygonSdf, SideBoundary, polygon_interface_velocity,
|
||||
polygon_signed_distance,
|
||||
};
|
||||
use rtx_fea::assembly::dof_mapping::DofComponent;
|
||||
@@ -334,7 +334,7 @@ pub struct Fsi2Harness {
|
||||
/// The deformable geometry AND its velocity, behind one lock: the
|
||||
/// fluid's per-step mask rebuild reads the polygon; the no-slip
|
||||
/// closure reads both.
|
||||
pub shared: Arc<RwLock<(Vec<(f64, f64)>, Vec<(f64, f64)>)>>,
|
||||
pub shared: Arc<RwLock<(PolygonSdf, Vec<(f64, f64)>)>>,
|
||||
pub spiked_total: Cell<usize>,
|
||||
}
|
||||
|
||||
@@ -377,8 +377,11 @@ impl Fsi2Harness {
|
||||
.expect("point A");
|
||||
|
||||
let zero_d = vec![0.0; 2 * interface.wetted.len()];
|
||||
// The polygon lives behind the lock as an INDEXED SDF
|
||||
// (bit-identical query; the brute-force walk was measured at
|
||||
// 51% of the fluid step, called for every mask cell and ghost).
|
||||
let shared = Arc::new(RwLock::new((
|
||||
interface.polygon(&zero_d),
|
||||
PolygonSdf::new(interface.polygon(&zero_d)),
|
||||
interface.walk_velocities(&zero_d),
|
||||
)));
|
||||
let sdf_shared = shared.clone();
|
||||
@@ -418,14 +421,14 @@ impl Fsi2Harness {
|
||||
solver.set_moving_body(
|
||||
EmbeddedBody::from_sdf(move |x, y, _| {
|
||||
let geometry = sdf_shared.read().unwrap();
|
||||
circle_sdf(x, y).min(polygon_signed_distance(&geometry.0, x, y))
|
||||
circle_sdf(x, y).min(geometry.0.signed_distance(x, y))
|
||||
})
|
||||
.with_surface_velocity(move |x, y, _| {
|
||||
let geometry = vel_shared.read().unwrap();
|
||||
if circle_sdf(x, y) <= polygon_signed_distance(&geometry.0, x, y) {
|
||||
if circle_sdf(x, y) <= geometry.0.signed_distance(x, y) {
|
||||
(0.0, 0.0)
|
||||
} else {
|
||||
polygon_interface_velocity(&geometry.0, &geometry.1, x, y)
|
||||
polygon_interface_velocity(geometry.0.vertices(), &geometry.1, x, y)
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -454,7 +457,7 @@ impl Fsi2Harness {
|
||||
/// Publish an interface geometry (+ velocity) to the fluid.
|
||||
pub fn set_geometry(&self, d: &[f64], ddot: &[f64]) {
|
||||
let mut geometry = self.shared.write().unwrap();
|
||||
geometry.0 = self.interface.polygon(d);
|
||||
geometry.0 = PolygonSdf::new(self.interface.polygon(d));
|
||||
geometry.1 = self.interface.walk_velocities(ddot);
|
||||
}
|
||||
|
||||
@@ -462,7 +465,7 @@ impl Fsi2Harness {
|
||||
pub fn measure_force(&self, solver: &EmbeddedPisoSolver, field: &FlowField) -> (f64, f64) {
|
||||
let mask = solver.mask().unwrap();
|
||||
let body = solver.body().unwrap();
|
||||
let vertices = self.shared.read().unwrap().0.clone();
|
||||
let vertices = self.shared.read().unwrap().0.vertices().to_vec();
|
||||
// Collect, then clamp, then integrate: the same 20x-median spike
|
||||
// clamp the coupling loads carry. Without it the REPORTED
|
||||
// drag/lift at large deformation are dominated by the rare wild
|
||||
|
||||
Reference in New Issue
Block a user