Commit Graph
3 Commits
Author SHA1 Message Date
Omar SobhandClaude Fable 5 327da7ff47 rtx-cfd: multigrid-PCG projection — 30x faster, same answers — and the CFD1 refinement study
Performance Benchmarks / Run Benchmarks (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
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (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
Falsifier 4 of the Turek–Hron geometry decision fired (the SOR projection
cost 0.09 s/step at 250x41 and an hour per run at 5 mm); this answers it.

solvers::incompressible::poisson: PoissonProblem (cell-centred five-point
SPD operator as per-cell face coefficients + Dirichlet diagonal extra +
active mask) and solve_multigrid_pcg — conjugate gradient preconditioned
by one V-cycle of geometric multigrid: aggregation by 2 per direction (odd
sizes absorbed, coarse cell active iff any child is), the Galerkin coarse
operator for piecewise-constant prolongation / summation restriction,
symmetric Gauss–Seidel smoothing, coarse correction scaled by 2 (Braess's
under-correction of unsmoothed aggregation; scalar, so the preconditioner
stays symmetric and positive on range(A)), L1 TRUE-residual stop with a
stagnation guard. Singular systems are handled per connected component of
the active cells (mean projection and level per pure-Neumann component;
the anchor's component to p[anchor] = 0). PoissonSolverKind::{Sor,
Multigrid} on PisoParameters / EmbeddedParameters; Sor is the default and
its code is byte-for-byte untouched; an unconverged multigrid solve falls
back to the SOR sweeps for that projection.

Verified (poisson/tests.rs, tests/poisson_equivalence.rs):
- PCG iterations to cut the residual 1e-8 on the closed Neumann box at
  32^2..256^2: 4, 4, 4, 4; ragged masked domains 8/8/8;
- manufactured recoveries to ~1e-14; Galerkin identity A_c v = R A P v to
  7e-15 on every level (masked, outlet column, non-uniform conductances);
  V-cycle symmetric to 1e-14; NaN-poisoned inactive cells untouched;
- two Neumann components with opposite imbalances, and a Dirichlet
  component beside an imbalanced Neumann one (review scenarios): converge,
  each component right up to its own constant;
- speed vs plain SOR at the same stop: 22.7x (128^2), 41x (256^2);
- same answers as SOR: PISO MMS 4.6e-8 relative, Taylor–Green divergence
  1.4e-9 every step, embedded-circle MMS 7e-8, no-body bit-identity with MG
  on both solvers, channel+outlet+circle 1.4e-10; CFD1 loads identical to
  four digits at 0.003 s/step vs 0.094 (30x).

CFD1 refinement study (tests/turek_hron_cfd.rs, three grids, 257 s):
h = 10 / 6.6 / 5 mm -> control-volume drag 15.6156 / 15.2829 / 15.0988 vs
14.2929 (+9.25 / +6.93 / +5.64%), apparent order 0.71, Richardson
extrapolate 14.04; surface route and lift not monotone (flag 2/3/4 cells
thick) — the test asserts the measured band at the finest grid.

Built with a 4-agent workflow (core, integration, refinement study,
adversarial review); the review found no defects and four risks, three
fixed here (per-component projection, one symmetric smoother-sweep
parameter, acting on `converged` with an SOR fallback) and one recorded
(isotropic aggregation loses grid-independence on anisotropic cells).

rtx-cfd 301 -> 318 green.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-20 10:20:25 -07:00
Omar SobhandClaude Fable 5 4bd98b5264 rtx-cfd + rtx-fsi: the added-mass piston — partitioned FSI on the real ALE fluid
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
CI / Clippy Check (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
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
The first coupled fluid-structure computation in the workspace, verified
against a closed form, and the first time rtx-fsi's added-mass claims run
against a real discretised fluid rather than a linear model map.

ALE extensions: per-side boundaries (Velocity / SlipWall / PressureOutlet)
and moving boundary lines. A moving Velocity side is a material wall whose
prescribed normal velocity must equal the line's own motion; a pressure
outlet takes Dirichlet p' = 0 in the projection (replacing the Neumann
anchor) with a zero-gradient predictor on its faces.

Fluid half verified alone (tests/ale_piston_channel.rs): prescribed piston
motion, slip walls, outlet. The incompressible rigid column is exact
DISCRETELY - continuity forces every u to the wall's discrete velocity
(8e-12) and the projected pressure is exactly linear with gradient rho
times the wall's backward-difference acceleration (2.5e-9).

Coupled benchmark (rtx-fsi/tests/piston_added_mass.rs): elastic piston
(Newmark average acceleration) against added mass rho*L*H at mass ratio
6.25, rtx-fsi's Subiterated driving a real fluid/structure pass per step:
- plain staggered diverges in 7 subiterations (Causin-Gerbeau-Nobile on a
  real solver);
- Aitken converges at 3.0 subiterations/step onto T = 1.07009 vs the
  closed form 1.06999 - 9.8e-5 relative, halving with dt;
- outlet flux matches the piston sweep to ~1e-9 every step.

Discrete-analysis finding: Newmark beta scales the staggered added-mass
threshold - the iteration gain is beta*m_a/(M + K*beta*dt^2), so the
continuous ratio 2.5 CONVERGES at beta = 1/4 (gain 0.625, measured ~17
passes/step) and the benchmark needs ratio 6.25 (gain 1.56).

Two real defects found and fixed, twelfth and thirteenth of the campaign:

1. rtx-cfd ale::advance re-stamped boundary faces at t_old from the
   current boundary function, which in a coupling loop carries the NEW
   interval's wall velocity - the predictor's old state had interior
   u = w0 but wall face u = w1, leaving an O(dt) pressure artifact
   confined to the wall-adjacent cells (p exact to 6e-11 everywhere
   except the wall cell at 4.7e-5). The start-of-step boundary faces are
   whatever the previous step's end-of-step application left there.

2. rtx-fsi aitken_factor guarded its denominator - a SQUARED residual-
   difference norm - against a bare f64::EPSILON, silently disabling
   Aitken below residual ~1e-8 and degrading to unit relaxation exactly
   in the well-converged regime; the repulsive fixed point then amplified
   1e-9 residuals back up and the coupling diverged. Third instance of
   the absolute-threshold species (NNLS, ECSW). The guard is relative
   now; aitken_is_scale_invariant pins it at initial residual 1e-9.

rtx-cfd 293 green (+1), rtx-fsi 29 green (+3). rtx-fsi's lib gains only
the relative guard; the coupling layer still depends on no solver
(rtx-cfd is a dev-dependency of its tests).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-20 06:10:13 -07:00
Omar SobhandClaude Fable 5 259c5baa63 rtx-cfd: ALE on a moving tensor-product grid, DGCL-exact by construction
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
CI / Build (macos-latest) (push) Canceled after 0s
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (push) Canceled after 0s
The first brick of the Turek-Hron frontier: PISO (explicit conservative
predictor + SOR projection) generalised to a staggered grid whose x- and
y-lines move arbitrarily each step while the domain boundary stays fixed.

The discretisation choice that carries everything: time-averaged face
areas (A^n + A^{n+1})/2 in both the fluid fluxes and the face-swept
volumes. For tensor-product motion the discrete geometric conservation
law then holds as an algebraic identity, so uniform flow is a
machine-precision fixed point, not a truncation-order one:

- DGCL test: uniform (0.7, -0.4) on a 16x12 grid with interior lines
  wiggling out of phase, 400 steps: max deviation 7.9e-15 (~35 ulp).
  Negative control with end-of-step areas (per-step cell error exactly
  dw*dh/V, the cross term the identity absorbs): 1.5e-2 - a 1e12
  separation, so the test can fail.
- Degeneracy: zero motion on a uniform grid vs fixed-grid PISO over
  Taylor-Green steps: max difference 2.2e-16 - one ulp - pinning every
  geometric generalisation to the verified implementation.
- Physics under motion: Taylor-Green on the wiggling mesh, L2 error
  2.42e-2 -> 1.07e-2 (n=16 -> 32, order 1.17); moving-mesh error at
  n=32 sits below the fixed-mesh 1.1532e-2 (PISO's published value to
  four digits); energy decay unchanged by the motion.

One trap documented in the test: the projection's inner-stop floor
(0.1 * tolerance * reference_flux) at an engineering tolerance lets a
one-sweep partial p' accumulate into p, whose gradient perturbs the
velocities at ~1e-11 with the geometry blameless. The DGCL run must use
a rounding-level tolerance because machine-precision preservation is the
claim under test. Measured: 3.6e-11 at tol 1e-9, 7.9e-15 at 1e-13.

Incompressibility needs no mesh-velocity term: subtracting the GCL from
moving-cell mass conservation leaves plain div(u) = 0 on the current
geometry, so the projection is the fixed-grid one with non-uniform
coefficients.

292 rtx-cfd tests green (288 + 4).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-20 05:31:12 -07:00