eba2f61ddfaa888f6208aff5caed0c7b112c95b1
421
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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]> |
||
|
|
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]>
|
||
|
|
8071d5888d |
rtx-fea: ECSW model-order reduction — POD-Galerkin plus hyper-reduction, verified end to end
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 third Farhat gap. New rtx_fea::mor module:
- pod::pod_basis — orthonormal SVD basis with an energy-criterion
truncation. Verified: rank-2 data yields exactly 2 orthonormal modes that
reconstruct every snapshot to machine precision; a loose tolerance
truncates a dominant-mode-plus-noise set to one mode.
- nnls — Lawson-Hanson non-negative least squares with the early stop that
makes ECSW work: iteration ends at the requested residual, and the
active-set structure caps the support at one column per outer iteration,
so sparsity falls out of the stopping tolerance. Verified against KKT
conditions, exact positive solutions, negative-clipping, and a
sparsity-vs-tolerance case. Its thresholds are RELATIVE to the problem's
own scales — the first version used absolute cutoffs (1e-14) that
silently ended the iteration on ECSW's small-magnitude training systems
at 1.2e-3 instead of the requested 1e-4.
- ecsw::train_ecsw — element weights such that a small subset reproduces
the reduced internal force (the virtual work against the basis) over the
training snapshots. w = 1 solves the system exactly by construction, so
it is always consistent; nonnegativity is what keeps a sampled element
from producing energy.
- reduced::ReducedNonlinearModel — Newton in POD coordinates, assembling
either every element (POD-Galerkin) or the ECSW sample, on the same
per-element force/tangent machinery the nonlinear analysis uses.
End-to-end verification (tests/ecsw_mor.rs): a clamped nonlinear block,
snapshots from a 4-point load sweep, evaluated at an UNSEEN load factor:
POD modes: 2 ECSW sample: 5 of 24 elements
training residual 2.2e-7 (requested 1e-4)
error vs full solve: POD-Galerkin 3.09e-7, ECSW 3.08e-7
hyper-reduction cost (ECSW vs full ROM): 1.6e-8
And the assertion with the most teeth: the same 5 elements with their
weights forced to 1 read a relative error of 1.22 — a completely wrong
field — so the accuracy is carried by the WEIGHTS, not by the subset
happening to be representative.
Scope, stated plainly: geometrically linear, materially nonlinear,
homogeneous Dirichlet only (no lifting); the basis lives on the free DOFs.
559 rtx-fea tests, 0 failing.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
b321a9aba7 |
rtx-cfd: Taylor-Green validates PISO's transient path — and fixes the projection's inner solve
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
With k = pi the decaying Taylor-Green vortex has zero normal velocity on the unit box for all time, so it fits the closed staggered domain exactly, with ZERO body force: convection is balanced identically by the true TG pressure and the decay comes from viscosity alone. This exercises exactly what the steady MMS harness cannot see — the time derivative, the unsteady pressure coupling and the projection's splitting error. The time-decaying tangential wall velocity enters by re-setting the wall hook each step. Measured (16/32/64, dt ~ h^2): L2 velocity 2.267e-2, 1.153e-2, 5.841e-3 — orders 0.97 and 0.98, first-order upwind's rate — and the kinetic-energy deficit against the exact e^(-4 nu pi^2 T) halves per refinement (0.0690, 0.0360, 0.0185; ratios 1.92, 1.95), within 2.3% on the finest mesh. Every step divergence-free to ~1e-7. Its first run caught two defects in the projection's inner solver: - The inner Gauss-Seidel stop summed the per-sweep iterate CHANGE — the same movement-not-residual pseudo-criterion the SIMPLE census flagged: slow modes move little per sweep while their residual is still large. - Plain GS contracts smooth modes by only 1 - O(h^2) per sweep, so the 400-sweep cap left max |div u| ~ 1e-2, GROWING with mesh size (8e-3 at 16^2 to 2e-2 at 64^2). The inner stop now measures the true equation residual, the sweep is SOR at the optimal Poisson factor omega = 2/(1 + sin(pi h)), and it converges relative to each projection's own source with a floor tied to the outer mass tolerance — so a long steady march no longer burns a hundred sweeps per step polishing negligible corrections. The steady MMS harness had masked all of this: a march to steady state iterates the projection to death regardless, which is why its divergence read 1e-9 while a 205-step transient left 1e-2. mms_piso's steady-state criterion is 1e-6 (was 1e-7): per-step projection noise at the mass tolerance floors |du/dt| just below 1e-6, and the L2 errors under measurement are 1e-2 to 1e-3. Its results are unchanged to six figures and still match SIMPLE's. 288 rtx-cfd tests, 0 failing. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
d8a30db155 |
rtx-cfd: Ghia Re=400 as a quantitative claim — and the stopping-tolerance trap
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
The Re=400 lid-driven cavity, 128^2 TVD on an exactly-unit domain, sampled
on the staggered faces that lie exactly on the centrelines, against Ghia,
Ghia & Shin (1982) — reference values sourced from two independent
transcriptions that agree digit for digit (Mramor/Vertnik/Sarler CMC 2013
Table 1, and the ivan-pi benchmark collection):
u_min -0.32667 at y = 0.2852 (Ghia: -0.32726 at 0.2813 — 0.18%)
v_min -0.45024 at x = 0.8633 (Ghia: -0.44993 at 0.8594 — 0.07%)
v_max 0.30044 at x = 0.2305 (Ghia: 0.30203 at 0.2266 — 0.53%)
max |u - Ghia| over 15 profile stations: 0.0051
Ghia's own values carry ~0.3% discretisation error (Sahin & Owens 2003 put
u_min at -0.32838), so this is at the reference's own accuracy.
The finding worth the commit message: the first run used the Re=100 test's
residual tolerance of 1e-4 and read u_min = -0.31987 — "converged", 2.3%
shy — and refining to 192^2 made it WORSE (-0.30879, profile deviation
doubled from 0.034 to 0.074). The residual had dropped below tolerance
while the field was still developing, and the effect grows with mesh size
because SIMPLE's per-iteration contraction weakens as h -> 0: at fixed
residual tolerance the finer mesh stops at an EARLIER stage of convergence.
Tightening the stop (3e-5, then 1.5e-5, until the movement per halving fell
below the reference's own error) was the fix, and the test's bands are set
so the premature-stop state fails all of them. "The residual converged"
must never stand in for "the answer stopped moving".
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
4da70faa1e |
rtx-fea: QM6 as an opt-in bending path; cantilever pinned to Euler-Bernoulli directly
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 QM6 incompatible-modes stiffness existed and was verified
(compute_stiffness_matrix_incompatible) but nothing could reach it: the
assembler always routed Quad4 through the compatible element. AssemblyOptions
gains use_incompatible_modes (default false — every existing matrix is
byte-identical, which the manufactured-solution verification depends on),
threaded through GlobalAssembler into StandardFiniteElement; element types
QM6 does not apply to keep their standard stiffness either way.
What it buys, measured on the cantilever first bending mode against
Euler-Bernoulli's 40.3848 Hz:
mesh QM6 (error) compatible (error)
8x2 40.4020 (+0.04%) 81.8102 (+102.6%)
16x4 40.3402 (-0.11%) 53.8022 (+33.2%)
32x8 40.3242 (-0.15%) 44.0796 (+9.2%)
The frequency is now asserted against the closed form directly (0.5% band)
instead of as convergence-from-above, plus the condensation theorem — QM6
can only soften, so its frequency must sit at or below the compatible one on
every mesh. The slight undershoot on finer meshes is physical: the 2-D solid
carries the transverse shear flexibility the beam theory neglects.
552 rtx-fea tests, 0 failing.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
6510045b5d |
rtx-fea: wire NonlinearStaticAnalysis — Newton on the consistent tangent, MMS-verified at second order
Documentation / Build API Documentation (push) Canceled after 0s
Documentation / Build User Guide (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
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
NonlinearStaticAnalysis::run returned DVector::zeros unconditionally, like ModalAnalysis and DynamicAnalysis before their repair. It is now full Newton-Raphson on R(u) = f_ext - f_int(u): - ElementMatrixComputer::compute_internal_force_and_tangent integrates f_int = int(B' sigma dV) and K_T = int(B' D_T B dV) in ONE quadrature sweep from a constitutive closure in the element's reduced Voigt space — computing both together is what keeps the tangent consistent with the stress, which is what quadratic convergence rides on. - materials::reduced_constitutive bridges the Material trait (Voigt-6) to that closure: 3-D passes the total strain straight through; 2-D supports the linear plane-stress closed form and refuses nonlinear materials explicitly, since plane-stress condensation of a general law needs a per-point iteration that is not implemented yet. - Dirichlet DOFs are held at their (load-scaled) values and Newton runs on the free DOFs, so the prescribed motion enters through f_int itself — no K_fc bookkeeping to get wrong. Body force enters via set_body_force, the same hook pattern the CFD solvers use for manufactured solutions. Uniform load stepping; other strategies and quasi-Newton refuse explicitly. - StandardFiniteElement::compute_internal_forces, previously a zeros stub, now delegates to the same machinery. - Mesh::validate is now called in run() (the old TODO), and NonlinearConfig gained a Default. Verified two ways (tests/nonlinear_static.rs): - Equivalence: with LinearElastic the loop lands on the directly assembled linear solution to 1e-10 in exactly one Newton step — same B, quadrature and solver, so any disagreement is the nonlinear assembly. - Manufactured solution with a genuinely nonlinear material (energy W = 1/2 e'De + alpha/3 I1^3, so stress and tangent are exact derivatives; body force by central differences of the closed-form stress): L2 errors 6.032e-2, 1.780e-2, 4.595e-3 on 2/4/8 Hex8 — observed orders 1.76 and 1.95, climbing to the theoretical 2. The forcing contains the nonlinear term, so the order is reachable only if it is solved; an inconsistent tangent is caught separately by the iteration-count bound. This unblocks ECSW model-order reduction, which needs a working nonlinear solve underneath it. 551 rtx-fea tests, 0 failing. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
e94ad1be6b |
rtx-cfd: Poiseuille closed-form validation with exact-zero assertions
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
Plane channel driven by a uniform body force: u(y) = G/(2mu) y(1-y), v = 0,
p exactly constant. Convection vanishes identically, so this isolates
diffusion, the half-cell wall treatment and the pressure coupling — and two
of the three answers are exact zeros, which no benchmark comparison offers.
The ends are clamped to the profile the DISCRETISATION prefers — the 1-D
tridiagonal with half-cell wall closures, solved directly in the test —
rather than to the continuous parabola. That makes (u_hat, 0, const) an
exact fixed point of the 2-D discretisation, and the solver must sit on it:
|u - u_hat| ~ 1e-10, max |v| ~ 1e-10, p spread ~ 8e-10 (16^2)
A first version clamped the ends to the continuous parabola instead; the
O(h^2) incompatibility between that profile and the discrete one drove a
weak secondary flow near the ends (max |v| = 1.3e-3) — a property of the
mismatched boundary data, not of the solver, recorded in the test docs so
nobody rediscovers it as a bug.
The wall treatment's own truncation is measured in isolation as
|u_hat - parabola|: 3.906e-3 at 16, 9.766e-4 at 32 — refinement ratio
exactly 4.00, second order, in closed form c h^2 / 4.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
9b097fca0d |
rtx-cfd: PISO validated by manufactured solution — after fixing the inverted projection
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
PisoSolver was the only major solver in the workspace with no verification of any kind. Writing the MMS harness for it (tests/mms_piso.rs) and inspecting the implementation found the census's defect species again: - The pressure correction had its SIGN inverted: it solved -lap(p') = +rho div(u*)/dt and then corrected with u = u* - (dt/rho) grad(p'), so each projection DOUBLED the divergence instead of removing it. - The momentum sweeps froze the near-wall lines (1..ny-1) and the pressure correction skipped the outer ring of cells (1..nx-1) — both exactly the defects repaired in SIMPLE. - The "explicit" predictor read neighbours the same sweep had already overwritten, so the step depended on sweep order. - The pressure gradient was dropped entirely on the last interior face. Rewritten as a genuinely explicit predictor plus anchored-Neumann projection on the staggered grid, with the conventions SIMPLE now embodies: near-wall lines are unknowns with half-cell wall diffusion, continuity on every cell, boundary faces are prescribed data. Momentum-source and wall-velocity hooks added so the manufactured solution can reach it. Measured (16 -> 32 -> 64): L2 velocity 3.516214e-2, 1.953750e-2, 1.037512e-2 — orders 0.85 and 0.91, first-order upwind's rate — with max |div u| ~ 1e-9 in every cell. The errors agree with SIMPLE's on the same meshes to six or seven significant figures: an implicit under-relaxed outer iteration and an explicit time-marching projection land on the same discrete steady solution, which is what sharing a spatial discretisation must produce and is very hard for two independently wrong solvers to fake. 285 tests, 0 failing. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
796cf173e6 |
rtx-cfd: second-order convection by deferred-correction TVD; MMS order 1.84, cavity closes on Ghia
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
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
First-order upwind's O(h) numerical viscosity was the measured limit on the
whole discretisation: MMS order ~0.9 at Re = 20 against 2.05 in the Stokes
limit. This adds a ConvectionScheme parameter to SimPLE — Upwind (default,
behaviour unchanged), TvdVanAlbada, TvdVanLeer — implemented by deferred
correction: the upwind operator stays implicit, so a_p = sum(a_nb) and
diagonal dominance survive unconditionally, and the limited
high-order-minus-upwind flux difference enters the source explicitly at the
current iterate. At a fixed point the two agree, so the converged answer is
the TVD discretisation. Faces whose far-upwind node lies outside the domain
fall back to pure upwind; wall faces pass no mass, so no correction enters.
Measured by the manufactured solution (van Albada, 16 -> 32 -> 64):
L2 velocity 1.325e-3 4.406e-4 1.232e-4 orders 1.59, 1.84
(upwind) 3.516e-2 1.954e-2 1.038e-2 orders 0.85, 0.91
The error is 27x to 84x below upwind's at equal resolution, the order climbs
toward 2 (the shortfall is limiter clipping plus the boundary fallback, both
of which shrink with h), the pressure error falls at the same rate, and
continuity still holds to solver tolerance in every cell.
On the Re = 100 lid-driven cavity at 65^2 the centreline minimum moves from
-0.1932 (upwind) to -0.2036 against Ghia's -0.2109 — 59% of the remaining
gap closed at equal resolution, converged in 790 iterations — and the vortex
position moves from 0.5000 to 0.4844 toward Ghia's 0.4531. Both new cavity
bounds exclude the upwind values, so falling back to first order fails them.
284 tests, 0 failing.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
87cf392556 |
rtx-fea: re-enable the remaining CPU test modules; fix three real defects they caught
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
All 33 remaining #[cfg(disabled)] test modules outside the GPU cluster are now enabled: assembly (dof_mapping, constraints, global assembly), boundary (mod + dirichlet/neumann/robin/thermal/contact), analysis (mod + static), materials (mod, linear_elastic, hyperelastic, plasticity), elements (mod, element_matrices, isoparametric, jacobian, quadrature), mesh (element_types, connectivity, topology, topology_repair), solvers (mod, direct, iterative, nonlinear) and lib.rs. Lib tests 117 -> 335, stable across repeated runs. Only gpu_solver_tests and the GpuMeshData fixture stay disabled — they need CUDA hardware and belong to the GPU tranche. Three real defects found by the newly-compiling tests, each fixed: - Direct solvers reused factorizations keyed on matrix SIZE alone. In a Newton loop the Jacobian changes every iteration but never its dimension, so LuDirect/CholeskyDirect/LdltDirect silently solved with the first iteration's factorization forever — Newton on x^2-4 crawled to x=1.955 in 1000 iterations instead of converging in 5. Invisible in single-solve linear analysis, which is why every green test passed over it. solve() now factorizes the matrix it is given. - AdaptiveQuadrature's refinement re-integrated the WHOLE domain once per subdomain, so each level multiplied the estimate by the subdomain count: integrating e^x over [-1,1] at tolerance 1e-10 returned ~75 instead of 2.35. The recursion now descends into each sub-box with its share of the error budget. - compute_skewness read Jacobian columns as coordinate-line tangents, but the trait's jacobian() stores tangents in ROWS: on a sheared parallelogram whose tangents meet at 14 degrees it reported skewness 0.43 instead of 0.84 — measuring per-component gradients, not mesh skew. Fixtures corrected rather than the code where the fixture was wrong: sigma_yy ~ 0 asserted uniaxial-stress physics on a uniaxial-strain state (exact Lame values now asserted); an "unstable" orthotropic parameter set that satisfies the determinant stability condition (delta = 0.187 > 0); a unit-cube hex Jacobian of 1.0 that assumed a unit reference element (it is 0.125 from [-1,1]^3); a "distorted" quad whose centre Jacobian is exactly orthogonal, asserted as skewed (flattening and shearing now tested separately); a quality score below the implementation's own calibration; Rayleigh damping fed the scalar-field mass (now expanded via the Kronecker identity, with C = alpha*M + beta*K asserted entry-wise); an element factory required to construct Point/Line types that have no implementation; and DOF counts that encoded the repaired 3-DOFs-per-node-on-2-D defect. MaterialDatabase::add_material call sites updated to the (id, material, name) signature; ConnectivityInfo::build takes elements only; TopologyRepair::triangle_quality (normalized 4*sqrt(3)*A/sum(a^2)) added for the repair tests; create_subdomain_rule_* widened to pub(super) for the quadrature tests. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
8495a690d9 |
rtx-fea: build the missing mesh-generation APIs and re-enable 8 test modules
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
The largest cluster of the 128 compile errors behind the disabled test modules was one missing API family. Now built, each with invariant tests a plausible-wrong mesh fails: - Rectangle::generate_quad_mesh / generate_tri_mesh — structured grids, CCW elements, exact area sums asserted - Circle::generate_tri_mesh — centre fan plus ring bands; tiles the inscribed polygon exactly - Box3D::generate_hex_mesh / generate_tet_mesh — the tet split is the Kuhn/Freudenthal 6-tet subdivision, conforming across cells, positive volumes summing exactly to the box - Sphere::generate_tet_mesh — concentric UV shells, centre fan, prisms split by the Dompierre smallest-index diagonal rule so neighbouring prisms agree; conformity and closed-boundary asserted via face counting - Mesh::validate — empty/inconsistent/orphan checks plus signed-area orientation for planar Tri3/Quad4, which is what an inverted connectivity fails - Mesh::find_boundary_edges / find_boundary_faces / calculate_edge_normal, Node::distance_to / with_label Re-enabling the tests found a real defect: geometry::Face derived order-sensitive PartialEq/Hash, so the same face listed by two adjacent elements (different start node, opposite winding) never compared equal. A 2x2x2 hex mesh reported 32 boundary faces instead of 24 — and find_boundary_nodes in 3-D and the 3-D surface-area statistic sit on the same counting. Face identity is now canonical (sorted ids; quads keep their diagonal pairing). Partitioning: the fixtures targeted an instance API that never existed — MeshPartitioner::partition is an associated function. Two real gaps fixed: interface_elements was never populated, and requesting more partitions than elements produced useless empty partitions (now clamps). Fixtures corrected rather than the code where they encoded abandoned designs: global DOF numbers on nodes (DofMap's job), element thickness/property bags nothing reads, a 0-to-1 quality score that never existed, and a clockwise sliver that validate now rightly rejects. The GPU data conversion test stays disabled with the GPU solver tranche. Lib tests 72 -> 117, stable across 5 runs, all integration suites green. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
1a740e0b2c |
rtx-cfd: the wall treatment is second order, not first — correct the record
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
The manufactured-solution test carried a hypothesis for why the observed
order sits below 1: that `(u_P - u_wall)/(dy/2)` approximates the wall
gradient at y = dy/4 rather than at the wall, making the near-wall rows
first order.
Measuring in the Stokes limit refutes it. With convection negligible every
remaining operator is second order, so the observed rate there reports the
wall treatment directly:
rho = 1.000 (Re = 20.00) 3.52e-2 1.95e-2 1.04e-2 orders 0.85 0.91
rho = 0.001 (Re = 0.02) 2.21e-3 5.35e-4 1.28e-4 orders 2.05 2.06
2.05 and 2.06. The half-cell wall term is second-order accurate and the
Stokes discretisation reaches its nominal rate. The shortfall at Re = 20 is
first-order upwind and nothing else, which is what a first-order convection
scheme is supposed to give.
Comment corrected rather than left standing: a plausible explanation that
happens to be wrong is worse than none, because it sends the next person
to fix something that is not broken.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
698c844926 |
solvers: near-wall momentum, Newmark dynamics, QM6, and MMS across elements
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
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
Four parallel work items plus two defects found while integrating them.
561 -> 592 tests, 0 failing, verified stable over repeated runs.
## rtx-cfd: solve the near-wall velocity lines
Every u row sits at y = (j+0.5) dy and every v column at x = (i+0.5) dx --
strictly interior. The sweeps froze rows 0 and ny-1 and columns 0 and
nx-1 and treated whatever was stored there as a boundary condition, which
imposed wall values half a cell inside the domain. They are now unknowns,
with the wall entering through the control volume's half-cell conductance
(mu dx / (dy/2)), zero convective flux through the wall, and the wall's
tangential velocity in the source.
That in turn makes continuity enforceable on every cell, with a neighbour
coefficient zero only for a genuine boundary face. Extending continuity
had been tried before and broke convergence; it works now because the
near-wall lines are no longer frozen. Order matters here.
Manufactured solutions, which is how any of this is known:
n L2 velocity order max |p - p_exact|
16 3.516212e-2 - 9.245576e-2
32 1.953751e-2 0.85 5.225739e-2
64 1.037523e-2 0.91 2.796415e-2
Velocity error is 7.4x smaller at n=16, and the observed order rises from
0.48 toward 1. The pressure error was 0.408 -> 0.624 -> 0.756, *growing*
with refinement; it now falls. Divergence on the outer ring of cells goes
from 1.0e1 to 2.5e-10.
A separate defect found on the way: u_source_term was computed and never
called, so the x-momentum equation carried no body force at all while the
y-momentum one did. That is exactly the u-versus-v asymmetry the earlier
diagnosis had flagged as an unexplained clue.
Cavity at 65^2, against Ghia's u_min = -0.2109 at y = 0.4531:
-0.1792 at 0.3906 before, -0.1932 at 0.5000 after, in 733 iterations
rather than 971.
The cavity test now sets FreeSlipWall on all four sides plus the lid
through the new set_wall_velocity hook. That is not a weakened benchmark:
on a staggered grid the only velocity component living *on* a boundary is
the normal one, which is what FreeSlipWall prescribes, and the tangential
no-slip arrives through the half-cell wall term with wall velocity zero on
the three stationary walls. Prescribing whole u rows and v columns, as
before, pins lines half a cell inside the domain and over-determines the
cells beside them once every cell has a continuity equation.
## rtx-fea: DynamicAnalysis, previously a stub returning zeros
Newmark-beta in acceleration form -- the displacement form divides by
beta dt^2, singular at beta = 0 -- with Rayleigh damping, the effective
matrix Cholesky-factorised once and reused. Initial acceleration is solved
from M a0 = F0 - C v0 - K u0 rather than assumed zero, which would destroy
the second-order rate.
Verified two ways that cannot both be faked: against the closed-form
single-degree-of-freedom response, undamped and damped, with the measured
order of accuracy; and against the free-vibration period of the same bar
whose modal frequencies are already validated. Time domain and frequency
domain come from different code paths.
## rtx-fea: QM6 incompatible modes
Wilson's Q6 with Taylor's correction, added alongside compute_stiffness_
matrix rather than replacing it -- the existing method is byte-identical,
which matters because the manufactured-solution verification depends on
it. Internal modes statically condensed; the incompatible strain block
evaluated at the element centre, which is what makes the patch test pass
on distorted elements.
## rtx-fea: manufactured solutions across the element library
Quad4 order 2.00 Tri3 order 1.98
Quad8 order 3.00 Hex8 order 1.96 (new 3-D solution)
Each element asserts its own theoretical rate.
## Two defects found while integrating
Reverse Cuthill-McKee node ordering was nondeterministic. All three of its
orderings -- seed selection, neighbour ordering, and the trailing sweep --
were decided by HashMap/HashSet iteration order, which std randomises per
process. On a rectangular mesh every corner ties at minimum degree, so two
calls to displacement_only on the same mesh in the same process returned
different DOF indices for the same node, agreeing in only 5 of 20 measured
runs. Ties now break by node id. This surfaced as a coin-flip test failure
-- 12 in 25 runs -- and would have been dismissed as flaky rather than
diagnosed had the integration pass not re-run it.
Quadrature: triangle(3) weights summed to 0.25 against a reference area of
0.5, and tetrahedron(3) to 1/36 against a volume of 1/6. Both divided
weights that were already tabulated for the reference measure by that
measure again, so both rules integrated everything to a fraction of its
value -- invisibly, since a scaled quadrature leaves the stiffness matrix
symmetric, the mass matrix positive definite and the rigid-body modes
exact. New test asserts every rule integrates 1 to its reference measure,
across every family and order, plus Gauss-Legendre exactness to degree
2n-1.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
b5814a304f |
rtx-cfd: manufactured solution finds the diffusion conductances were 1/h too
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
large
Applies MMS to the SIMPLE solver. It found a major discretisation error on
the first run, which is the point of the method.
The diffusion conductances read `mu / dx` and `mu / dy`. Finite volume
requires `Gamma * A / delta` — the face area over the distance between the
nodes it separates — so they should be `mu * dy / dx` and `mu * dx / dy`.
The face area was missing entirely, making viscosity too large by a factor
of `1/h`: sixty-five times on a 65x65 mesh. Every other term in the
equation was already a force (`dp * dy` for pressure, `rho u dy` for the
convective flux), so the mismatch was confined to diffusion.
The consequence was that the solver ran at an effective Reynolds number
far below the one requested. Before the fix the manufactured-solution
error did not reduce under refinement at all — observed order about -0.05,
because the spurious viscosity grows with the mesh. After it, the error
falls monotonically.
This also explains an apparent regression that is really a correction.
The cavity vortex position moved from y = 0.484 to y = 0.391 against
Ghia's 0.4531, which reads as worse agreement. It is not: a strongly
over-diffusive cavity approaches Stokes flow, whose vortex sits near
mid-height, so the old number was closer to the reference than the scheme
deserved. Correcting the viscosity exposed the discretisation's own error.
The test now states that disagreement plainly rather than asserting a band
around the reference.
What MMS reports now, and it is not yet good enough:
n = 16 L2 velocity error = 2.586104e-1 order -
n = 32 L2 velocity error = 1.797373e-1 order 0.52
n = 64 L2 velocity error = 1.277188e-1 order 0.49
First-order upwind should give 1. It gives about 0.5, and the u component
is markedly further from exact than v on the same mesh. Both say there is
at least one more defect in the discretisation or its boundary treatment,
and the asymmetry between the two momentum equations is the clue. The test
asserts only monotone error reduction — what is established — and records
the shortfall, because asserting a rate the solver does not achieve would
either redden the suite or invite someone to weaken it later.
This changes the plan: raising the observed order to 1 is now a
precondition for the second-order convection work rather than a
consequence of it. There is no value in adding a higher-order scheme to a
discretisation that has not demonstrated first order.
Supporting changes:
- `SimpleSolver::set_momentum_source` applies a volumetric body force,
which is what lets a manufactured solution be imposed at all.
- Divergence is now detected by growth, not only by NaN. The 8x8 case at
Reynolds 10^6 reached 1e149 before anything caught it, because
`is_finite` stays true right up until it does not.
- `test_simple_solver_workflow` specified water properties on a unit
domain, which is Reynolds 10^6 on ten cells: no steady laminar
solution exists and the solver diverges on it, correctly. It passed
only while the excess diffusion stabilised it. Now set to Reynolds 100.
561 tests across the three crates, 0 failing.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
10e5f9cb90 |
rtx-cfd: fix the cell-centre velocity interpolation, which was half a cell out
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
`get_velocity_at` averaged u-faces `i - 1` and `i` to report the velocity
at cell `i`. On this staggered layout `u` is `(ny, nx + 1)` and cell `i`
is bounded by faces `i` and `i + 1` -- which is the convention
`compute_mass_source` uses to form the divergence, and therefore the one
that defines the grid. The two disagreed by one index.
Consequences: every profile read through this function was shifted half a
cell west of the field the solver actually computed, the first and last
cells were special-cased to a single face, and the outermost face was
never read at all.
It is a diagnostic path rather than a solve path -- the residuals are
byte-identical before and after -- but the cavity comparison against Ghia
is taken through it, so the reported vortex position was affected. The
corrected grid study, unchanged in the solve:
n u_min y
17^2 -0.1257 0.4375
33^2 -0.1550 0.4688
65^2 -0.1743 0.4844
97^2 -0.1825 0.5000
Ghia -0.2109 0.4531
The shift matters most where the grid is coarse and washes out under
refinement, which is what a half-cell offset should do.
Found while establishing where each staggered variable physically sits, a
prerequisite for applying the method of manufactured solutions to this
solver.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
8615fc5783 |
rtx-fea: verify elastostatics by manufactured solution — second order confirmed
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
Adds the Method of Manufactured Solutions to this crate, and it immediately
paid for itself by finding a bug that every existing test missed.
MMS asserts something stronger than "close enough to a value someone
believed": that the discretisation converges to the exact solution at the
rate the theory predicts. Choose a smooth field, substitute it into the
governing equations, and whatever they fail to balance is the body force
that makes it exact. Solve, refine, read off log2(e_h / e_h/2).
Observed order for Quad4 displacement in L2:
n = 8 L2 error = 7.816681e-3 order -
n = 16 L2 error = 1.962845e-3 order 1.99
n = 32 L2 error = 4.912786e-4 order 2.00
(n = 64 reads 2.00 as well, at ten times the cost)
That verifies the whole chain at once -- element matrices, quadrature,
Jacobian, assembly, DOF numbering, constraints and the linear solver --
against a solution none of them can represent exactly. It is the check
that none of the sixteen defects fixed in this crate would have survived.
The manufactured field is u = sin(pi x) sin(pi y), v = x^2(1-x) y(1-y):
smooth, not in the bilinear element space, with the two components
different in form and a non-zero shear strain, so the shear block of the
constitutive matrix is exercised rather than skipped.
Found by it: `compute_shape_functions` inferred how many parametric
coordinates to pass from the coordinate *values* --
match coords.eta() {
0.0 if coords.zeta() == 0.0 => vec![coords.xi()], // 1 component
...
-- so any evaluation on an axis was handed a one-component slice, which
every 2-D and 3-D element rejects. That includes the element centre and
the middle point of every odd-order Gauss rule. It survived only because
the default 2-point rule never samples zero; asking for a 3-point rule to
integrate the error was enough to trip it. Dimensionality now comes from
the element, which is where it belongs.
Two prerequisites, both real functional gaps rather than test scaffolding:
- Consistent body-force integration. `BodyForceBC` distributed load as
force * volume / num_nodes, which is exact only for a constant force
on a symmetric element and otherwise first-order -- enough to cap the
measured order of the whole solver at 1 regardless of the element.
`ElementMatrixComputer::compute_body_force_vector` now integrates
the consistent form, taking the force as a closure so a spatially
varying load can be expressed at all.
- Non-homogeneous Dirichlet conditions did not exist.
`StaticLinearAnalysis` read the prescribed value out of the boundary
condition and discarded it, and `extract_free_system` built the
reduced right-hand side without the K_fc u_c coupling, so every
Dirichlet condition behaved as zero whatever the caller asked for.
`GlobalSystem::set_prescribed_value` and the coupling term close
that, reusing `extract_submatrix` and `multiply_vector` rather than
a dof-by-dof loop.
560 tests across the three crates, 0 failing.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
03a9bdf41f |
rtx-cfd: apply boundary conditions to u* before using its divergence
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
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
Closes the relaxation-factor dependence. Converged solutions are now
identical for velocity relaxation 0.3, 0.5, 0.7 and 0.9 -- bit for bit --
where they previously spread 18%.
The cause was ordering, not formulation. Boundary conditions were applied
only at the end of the iteration, so `copy_to_starred` snapshotted a
predicted field whose boundary faces held whatever the momentum sweep had
written there: values the wall overwrote with zero moments later. The
divergence of that field is the pressure equation's source, so those
un-constrained faces entered it as a spurious mass source, concentrated at
the two lid corners where the moving lid meets a stationary wall. The
swept value scales with the relaxation factor, so the spurious source did
too -- and so did the answer.
Diagnosis is worth recording because the symptom pointed away from the
cause. At the stalled state the interior momentum equations were satisfied
to machine precision at every relaxation factor: a fresh Gauss-Seidel
sweep moved the interior by 1e-15, the pressure correction was 1e-14, and
the momentum residual was 3.6e-16. The entire residual floor lived in the
*mass* term, and only that term varied with alpha -- 3.7e-4 at 0.3 against
1.6e-4 at 0.9. Each relaxation factor was converging honestly, to the
solution of a slightly different problem.
The correction also moves the cavity substantially closer to the reference,
because the spurious corner source had been suppressing the recirculation:
grid before after Ghia (1982)
17^2 -0.068 -0.123 -0.2109
33^2 -0.109 -0.154
65^2 -0.142 -0.174
97^2 -0.157 -0.182
Richardson extrapolation on the two finest grids now gives about -0.199
against Ghia's -0.2109, within 6%, with the remaining gap consistent with
first-order upwind's numerical viscosity. The residual floor falls roughly
linearly with mesh size (1.6e-3, 5.2e-4, 1.6e-4, 7.8e-5), which is the
signature of the corner singularity rather than of an unconverged solve --
the same one Botella & Peyret (1998) subtract analytically.
Two further fixes fell out of it:
- The solver returned NaN rather than reporting divergence. Asked for an
8x8 cavity at a Reynolds number of a million it now stops, says it did
not converge, and reports the last finite residual, instead of handing
back a field of NaN that poisons everything downstream. Previously the
false transient's large diagonal damped that case into crawling rather
than diverging, which hid it.
- `apply_boundary_condition` used `start_index` where it meant
`end_index` for the bottom wall. The other three arms are correct; with
both indices unset the default masked it.
558 tests across the three crates, 0 failing.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
2db4e28760 |
rtx-cfd: make SIMPLE a steady solver; the converged answer no longer depends
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
on the pseudo-time step Acting on a literature pass. Standard SIMPLE is a steady-state algorithm: it has no pseudo-time term, and stability comes from under-relaxation folded implicitly into the momentum coefficients. Ours had a false transient *and* an explicit post-hoc blend of the whole field, which is why the converged cavity solution varied with `time_step` -- something a steady state cannot legitimately do. Four changes, in the order they mattered: 1. The convergence measure was `|u - u_old|`, the change between successive iterates. That is not a residual: it reports how far the iteration moved, which depends on how heavily it is damped, and the damping was set by `dt`. Replaced with the imbalance of the discretised momentum equations, `|a_p u_P - sum a_nb u_nb - b|`, normalised by `sum |a_p u_P|` as CFD solvers conventionally report it. An unnormalised sum grows with the cell count and with `dt` through `a_p0`, so the same numeric tolerance meant a different thing on every grid. The residual is measured against the *unrelaxed* equation. Relaxation inflates the diagonal by 1/alpha and adds a matching source; reporting the relaxed system's residual makes one tolerance correspond to a different true error for each alpha. 2. Steady by default: `a_p0 = 0`, and Patankar's implicit under-relaxation -- `a_p / alpha` with `(1-alpha)/alpha * a_p * u_prev` added to the source. At a fixed point the two cancel exactly, so the converged solution is independent of alpha by construction. The explicit velocity blend is removed; it relaxed a second time and undid part of the continuity the pressure correction had just enforced. `steady: false` restores the transient term for genuinely time-dependent problems. Result: dt = 0.001, 0.01 and 0.05 now give bit-identical fields. 3. Dropped the net convective flux from `a_p`. It vanishes identically once continuity holds, but during the iteration it does not, and it can exceed the sum of the neighbour coefficients -- driving `a_p` through zero and the solve to NaN, which is what the workflow tests hit once `a_p0` was no longer there to mask it. Omitting it is what makes `a_p = sum a_nb` positive unconditionally. 4. Anchored one cell of the pressure correction. With velocity prescribed on every boundary the pressure equation is pure Neumann and singular; `p'` is fixed only up to a constant and Gauss-Seidel lets it drift. Enforcing solvability by subtracting the mean source is the textbook remedy and is wrong here -- this source is assembled from face fluxes that include the boundaries, so it need not sum to zero, and subtracting its mean injects a spurious source everywhere. Tried; it diverged. Anchoring a reference cell changes no pressure gradient, which is all the momentum equation uses. Also measured, and it settles the open question about Ghia: the under-prediction is numerical diffusion, not a defect. First-order upwind carries a numerical viscosity of about |u| dx / 2, which at 65^2 is 0.0078 against a physical 0.01 -- an effective Reynolds number near 56, not 100. Refinement moves the centreline minimum monotonically toward the reference: -0.068 at 17^2, -0.109 at 33^2, -0.142 at 65^2, -0.157 at 97^2, against Ghia's -0.2109, with the vortex position tracking 0.375 -> 0.406 -> 0.469 -> 0.490 against Ghia's 0.4531. The cavity test moves to 65^2 and asserts the vortex position tightly (0.40..0.52, Ghia 0.4531) while bounding the strength to the band first-order upwind can reach there. Its tolerance is 1e-4 rather than 1e-6: the two lid corners hold a velocity discontinuity whose discrete imbalance does not reduce with iteration, so the normalised residual floors near 7e-5. That is a property of the problem -- the same singularity Botella & Peyret (1998) subtract analytically -- and the physical assertions, not the stopping rule, are what establish correctness. Still open: converged solutions retain a dependence on the relaxation factor that the implicit formulation should have removed (-0.159 at alpha=0.3 against -0.134 at alpha=0.9 on 65^2, each stable to six decimals over 200k iterations). Recorded rather than papered over. 558 tests across the three crates, 0 failing. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> |
||
|
|
bfd9f4dfd2 |
rtx-cfd: repair the pressure-velocity coupling, LBM walls and mesh quality
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
Clears the rest of the quarantine. All three crates now run 558 tests
with 0 failures and no `#[ignore]` markers.
SIMPLE could not converge, and the reason was not slow convergence but
wrong physics.
The pressure correction equation used a bare Laplacian, 1/dx^2 and
1/dy^2, while the velocity correction divided by a_p = rho dx dy / dt.
SIMPLE requires these to be each other's inverse: substituting the
corrected velocities into continuity must reproduce the pressure
equation, which fixes a_E = rho d dy/dx with d = dV/a_p. The two
disagreed by roughly 1/(h^2 dt) -- about 2e4 on a 16x16 cavity -- so the
pressure correction was that many times too weak to enforce continuity.
The consequence was visible and specific. A lid-driven cavity at Re=100
produced a monotonic profile rising from 0 at the floor to 1 at the lid:
Couette flow, with no recirculation anywhere, and a peak pressure of
1.6e-4 against the rho U^2 scale of 1. The return flow in a cavity is
driven entirely by the pressure gradient, so with the pressure pinned
near zero there was nothing to turn the flow around. With the
coefficients made consistent the profile recirculates, the peak pressure
is 2.9, and the solver converges.
Also in SIMPLE:
- `p'` was never reset between outer iterations. It is a correction
that `pressure_update_step` folds into `p`, so carrying it forward
applied the same correction twice.
- The convergence measure was the inner Gauss-Seidel residual, which
goes to zero whether or not the flow satisfies continuity. Now the
mass imbalance.
- The velocity correction used only the transient part of a_p,
`rho dV/dt`, rather than the diagonal the momentum equation was
actually solved with.
- All four convective face fluxes were computed from a single
cell-centred velocity, so `fe` and `fw` were the same number, as were
`fn` and `fs`. Upwinding then picked the same direction on opposite
faces of the control volume. Now interpolated per face on the
staggered grid.
Not claimed: agreement with Ghia, Ghia & Shin (1982). The vortex centre
moves toward their y = 0.4531 under refinement (0.400 at 16^2, 0.419 at
32^2, 0.460 at 64^2) but the minimum centreline velocity reaches only
-0.130 against their -0.2109, and the converged field still depends
slightly on the pseudo-time step, which a true steady state cannot. The
cavity test therefore asserts what is established -- convergence,
recirculation, vortex position, and an O(1) pressure field -- and the
remaining gap is recorded in omni-cortex/docs/solver_status.md rather
than papered over with a loose tolerance.
LBM bounce-back was doing neither of the things its name claims. It was
written as assignment (`f[2] = f[4]`) rather than a swap, discarding the
population being reflected -- bounce-back is a permutation and conserves
mass exactly, so the domain leaked 0.013% of its mass every 100 steps and
would have kept draining. And the pairs used were 5<->8 and 6<->7, which
reverse only the wall-normal component: that is specular reflection, a
free-slip wall, so the no-slip condition the walls were supposed to
impose never held.
Mesh quality:
- Quadrilateral aspect ratio included the diagonals in the maximum but
not the minimum, so it could never return 1: a unit square reported
sqrt(2) and a 2:1 rectangle sqrt(5).
- Triangle aspect ratio used longest-over-shortest edge, which does not
detect the failure mode that matters. A sliver with vertices (0,0),
(10,0), (5,0.1) scores 2.0 -- indistinguishable from a healthy 2:1
triangle -- while its area is a twentieth of what its edges suggest.
Now the radius ratio R/2r, which is 1 for equilateral and 1250 for
that sliver, and which also fixes the quality histogram.
- StructuredMesh aspect ratio took bounding-box extents and guarded the
z-extent with `.max(1e-10)`. On a 2-D mesh the depth is exactly zero,
so the guard became the minimum and a unit square reported 2e10.
Mesh refinement produced meshes that failed their own validation.
`subdivide_triangle` reserved midpoint ids as `next_node_id + k`, then
advanced the counter by 3, after which `refine_cells` called `add_node`
and advanced it three more -- so every refined cell referenced vertices
three ids away from the ones actually created. Separately, the position
lookup selected by slot rather than by id ("This is simplified, should
look up correct midpoint"), so three of four sub-triangles had their
areas computed from the wrong points; the quadrilateral version mapped
every new id to the cell centre.
Fixtures corrected rather than tolerances loosened: a structured mesh
test asserted 0.16 for the average cell volume while the comment beside
it computed 0.25 from the node-count convention the code actually uses;
the Zou-He pressure test built a *velocity* boundary at u = 1.2, far
above the lattice speed of sound, making the density negative; and the
cavity-setup test required the lid to influence the domain centre 16
rows away in 10 steps, which exceeds the lattice propagation speed.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
e30cfe4ce9 |
rtx-fea: repair the element library; the crate is now green with no quarantine
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
Follows the assembly repair. Takes rtx-fea from 21 failures to 253 passing,
0 failing, 0 ignored, with every `#[ignore]` marker gone.
Shape function bugs, all found by one new test asserting two invariants
across the whole element library at once -- partition of unity, and that
the hand-written derivatives sum to zero. The second is the one that gets
skipped, and it is what caught Hexahedron20.
- Wedge15 summed to 2 at mid-height. Adding a node on a vertical edge
contributes L_i (1 - t^2) to the sum, so the two corners sharing that
edge must each give up half of it; the correction was absent. A
quadratic wedge that doubles every field interpolated through it.
- Hexahedron20 had sign errors in four hand-written corner
derivatives -- nodes 3 and 7 in dN/dr, nodes 1 and 5 in dN/ds. The
values were correct, so partition of unity passed; only the
derivative-sum invariant exposed it. The strain computed from this
element was wrong while its interpolation looked right.
- Quadrilateral9 emitted its shape functions in raw lexicographic
lattice order while Quad4 and Quad8 use the standard finite-element
order. A mesh written the usual way paired each node with the wrong
basis function, which at the element centre made the Jacobian exactly
singular.
- Pyramid13 was not a quadratic pyramid basis: it summed to 4 at the
element centre, and its `derivatives` allocated a 13x3 matrix then
wrote rows 13 through 15, having been copied from a sixteen-node
layout, so it panicked before the wrong values could be used. A
correct 13-node basis is rational, and there is no pyramid quadrature
rule to integrate it with, so implementing the basis alone would not
make the element usable. Both now report the gap explicitly rather
than panicking. Pyramid5 is unaffected and works.
Fixtures corrected rather than tolerances loosened:
- von Mises stress of an equal biaxial state expected 0, commented "no
deviatoric stress". Only a hydrostatic state has that. The correct
value is 100, and expecting 0 would mean a biaxially loaded sheet
could never yield. The unequal case expected |100-50|; the von Mises
stress is not a principal difference.
- A 3-point Gauss rule was required to integrate sin to 1e-10. No
correct implementation can. Replaced with a convergence assertion,
which a wrong rule cannot satisfy by luck.
- MathUtils::SMALL was asserted below EPSILON * 1000, which inverts the
relationship a practical zero-threshold needs.
- The Hex20 Jacobian test put all twelve mid-edge nodes at the origin,
commented "simplified for test". That is not a hexahedron, and its
mapping is genuinely singular; it only passed because of the
derivative sign errors above.
- ElementFactory was required to build every ElementType including
Point, which has no interpolation and is deliberately rejected.
MemoryInfo displayed decimal GB while its own test constructed binary
GiB, rendering an 8 GiB device as 8.59. Now GiB throughout.
test_mesh_has_real_algorithms searched the *text* of mesh/mod.rs for the
strings "add_node" and "add_element". It broke when those moved into
submodules, but the real problem is that a source-text search cannot tell
a working function from one returning zeros -- it passed throughout the
period when element matrices were a stub and quadrature returned no
points. Replaced with a test that builds a mesh and checks the result.
The crate doc example imported solvers::DirectSolver and
analysis::StaticAnalysis, neither of which has ever existed, so the
doctest never compiled. Replaced with a modal analysis that runs. Also
dropped the "Production Ready: No mocks, stubs, or TODOs - complete
implementation" line, and replaced it with what is actually validated and
what is not.
rtx-fsi unaffected at 26/26.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
4c2cea36aa |
rtx-fea: make the analysis stack produce physics, validated against closed form
The census found rtx-fea could not produce a non-zero answer for any
analysis type. Six defects sat between a correctly specified mesh and a
natural frequency, each of which alone was fatal. Every one was found by
writing the closed-form test first and confirming red.
1. Element matrices were a stub. StandardFiniteElement::
compute_element_matrices returned DMatrix::zeros for stiffness, force
and mass -- and it is what GlobalAssembler calls for every element, so
every global matrix in the crate was zero. Real quadrature-based
stiffness and mass already existed in ElementMatrixComputer; nothing
called them. Now wired, with the scalar mass matrix expanded by a
Kronecker product with the spatial identity to match the interleaved
per-node DOF layout its stiffness uses.
2. Quadrature returned no points. quadrature_rule built
QuadratureRule::new(vec![], ..). Every integration loop iterates over
rule.points, so an empty rule does not fail -- it skips the loop and
yields a zero matrix. Real Gauss rules for line, triangle, quad, tet
and hex existed unused; now dispatched by element type, with wedges as
the triangle-line tensor product and pyramids an explicit error rather
than an empty rule.
3. transform_derivatives computed J^-T * dN where dN is
(num_nodes x param_dim). By the chain rule it is dN * J^-1. The two
agree only when both are square and symmetric; for any element with
more nodes than parametric directions -- every element -- the old form
was a dimension mismatch that panicked inside BLAS.
4. MaterialDatabase::clone silently dropped every material, cloning
names only, because Box<dyn Material> is not Clone. GlobalAssembler is
constructed with materials.clone(), so every assembler ever built got
an empty database and every analysis failed MaterialNotFound on a
correctly specified mesh. Materials are immutable once registered, so
the map now holds Arc and cloning shares them.
5. displacement_only numbered three displacement components on a 2-D
mesh. Elements supply two, so assembly rejected every contribution.
6. to_dof_numbering pushed each node's DOFs in HashMap iteration order.
When that came out [v, u] the assembler wrote the element's u row into
the global v row. The result was still symmetric, still had the right
rigid-body null space and still summed to the right total mass -- it
simply described a structure with its axes transposed per node, and
get_dof(node, DisplacementX) then pointed at the wrong row so
constraints were applied to the wrong direction too. DofComponent now
carries a canonical_index and the DOFs are sorted by it.
ModalAnalysis is wired to real assembly and the repaired eigensolver, and
takes boundary conditions, which it previously had no way to accept. The
eigensolver now rejects a singular stiffness explicitly: try_inverse does
not fail on a matrix singular only to working precision, so an
unconstrained structure used to return rigid-body noise dressed up as
low-frequency modes.
Validation, 18 tests:
- Element matrices: rigid translation stores no energy, exactly 3
rigid-body modes in 2-D and 6 in 3-D, consistent mass integrates to
rho*V, mass positive definite, and K and M each scale only with the
property they depend on. A zero matrix passes symmetry and
does-not-crash checks, so these are chosen to be ones it fails.
- Modal, end to end: longitudinal modes of a fixed-free bar against
f_n = (2n-1)/(4L) sqrt(E/rho), within 1% on the first three, and
second-order convergence under refinement. Axial rather than
cantilever bending on purpose: Quad4 shear-locks, so a bending
tolerance would fail for a reason unrelated to correctness. Bending
is asserted as convergence from above instead, which is the honest
claim for a locking element.
Two fixtures corrected rather than tolerances loosened: integration_tests
expected 27 DOFs for a 9-node planar mesh (3 components per node), which
encoded defect 5 and contradicted comprehensive_tdd_tests asserting
num_nodes * 2 for the same situation.
rtx-fsi stays 26/26. No new failures; the rtx-cfd quarantine is
unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
cca29aac8f |
rtx-fea: repair the eigensolver, and stop the suite lying about the rest
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
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
CI / Format Check (push) Canceled after 0s
Lifts the 27 `#[ignore]` markers on rtx-cfd and rtx-fea. 21 of them fail;
6 were stale, marking components that have since been implemented. The
suite now reports the truth, which means it is red.
The eigensolver had three independent defects, each individually fatal.
Found by writing closed-form tests first and confirming red:
- The generalized reduction formed M^-1 K and ran Lanczos on it.
M^-1 K has the right eigenvalues but is not symmetric even when K
and M both are, and Lanczos assumes symmetry -- so it returned a
wrong answer rather than an inaccurate one. On a 2-DOF spring-mass
chain with M = diag(2,1) it gave 1.633 against an exact root of
1 - sqrt(2)/2 ~= 0.293. Replaced with the Cholesky reduction
B = L^-1 (K - sigma M) L^-T.
- Output was unsorted. nalgebra's symmetric_eigen gives no ordering
guarantee and none was imposed; modal analysis names modes by index,
so the ordering is part of the contract.
- Eigenvectors could not be transformed back out of the Krylov basis.
The Lanczos block was (n x num_iter) and the tridiagonal
eigenvectors (min(num_iter, k) x k); whenever those differed the
multiply panicked on a dimension mismatch -- that is, on every
problem with more DOFs than requested modes, which is every real
modal analysis.
Lanczos now runs shift-invert by default. Plain Lanczos converges to the
eigenvalues of largest magnitude and modal analysis wants the lowest, so
without it the solver returns the modes nobody asked for. Also switched
to full reorthogonalization, twice per step, so converged eigenvalues do
not reappear as ghosts indistinguishable from genuine repeated roots.
ModalResults computed f = sqrt(lambda / 2pi) instead of
sqrt(lambda) / 2pi. The two agree only at lambda = 2pi, so a smoke test
asserting a positive frequency would never separate them. A
`#[cfg(disabled)]` module in the same file asserted the correct formula
-- the module was disabled rather than the bug fixed. That module is
removed; tests/eigenvalue_closed_form.rs supersedes it with every
expected value derived analytically.
Corrected a fixture rather than loosening its tolerance:
implementation_tests expected the smallest eigenvalue of
tridiag(-1, 4, -1) at order 3 to be 4 - 2 sqrt(2) ~= 1.172. The
eigenvalues of tridiag(c, a, c) are a + 2c cos(k pi / (n+1)), so the
true value is 4 - sqrt(2) ~= 2.586. The test had been quarantined for
failing to match an expectation that was never right.
rtx-fsi is untouched and stays 26/26.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
|
||
|
|
9be5f4a68f |
rtx-fsi: partitioned fluid-structure coupling
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
CI / Test (ubuntu-latest) (push) Canceled after 0s
Performance Benchmarks / Run Benchmarks (push) Canceled after 0s
rtx-cfd (18,715 lines) and rtx-fea (36,576 lines) both exist and nothing connects them -- rtx-fea is commented out of rtx-cfd's dependencies. This is the coupling layer, and it is the piece Prof. Charbel Farhat's 2026 Guggenheim Medal citation is actually about. It depends on NEITHER solver. The properties that make a partitioned coupling correct -- conservation of force, moment and interface work -- are statements about the transfer operators alone, so they can be validated now, on solvers whose canonical-benchmark validation is still outstanding. Adapters to the concrete solvers belong above this. TRANSFER (transfer.rs). Weights satisfy two constraints: sum(w_i) = 1 partition of unity -> force conserved sum(w_i x_i) = x_face linear reproduction -> MOMENT conserved The second is the one that gets skipped. Inverse-distance weighting satisfies the first and generally violates the second, conserving force while corrupting moment -- which shows up as slow spurious rotation rather than as an obvious error. Underdetermined for >4 nodes, so it takes the minimum-norm solution w = A^T (A A^T)^+ b. That is a PSEUDO-inverse, and not for defensiveness. A wetted surface is a surface, so its nodes are usually planar, and for a planar patch the z constraint row is an affine multiple of the ones row -- A A^T is genuinely rank-deficient. The constraint is redundant there, not unsatisfiable. An ordinary inverse rejects the most ordinary interface there is; I found this because my first test fixture was collinear and the code correctly refused it. Constraints are then verified against the weights actually obtained, since a pseudo-inverse returns a least-squares answer whether or not the system was consistent. Motion transfer uses the TRANSPOSE of the load operator, which makes interface work conserved identically: (Hf).v = f.(H^T v). Any other pairing leaks energy every step, and the leak looks like physics until it destabilises. COUPLING (coupling.rs). Staggered and Aitken-relaxed subiteration. The decisive tests reproduce the added-mass effect: at a gain of 2.5 the fixed-relaxation scheme DIVERGES and is reported as CouplingDiverged rather than as an exhausted budget, and Aitken recovers the same case. A partitioned coupling that cannot reproduce its own classic failure mode is not being tested hard enough. Aitken is exact for a linear fixed point, so convergence is asserted at <=4 iterations -- pinning that this is the real delta-squared formula and not an under-relaxation that happens to work. SCOPE, stated up front in the crate docs: small-displacement transpiration coupling on a fixed mesh. Deliberately not ALE and not embedded-boundary, so the Discrete Geometric Conservation Law does not yet apply -- the mesh does not move. Large motion needs an embedded boundary treatment; that is the next phase, not an oversight. External comparator named at entry: Turek-Hron FSI2/FSI3, not yet reached. 26 tests written red-first; cargo test/fmt/clippy -D warnings clean. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> |
||
|
|
5155c081ca |
feat(mamba): GPU-accelerated backward pass (backward_cuda)
GPU Tests / Check GPU Availability (push) Successful in 0s
GPU Tests / CUDA Tests (11.8) (push) Skipped
GPU Tests / CUDA Tests (12.1) (push) Skipped
GPU Tests / Metal Tests (push) Skipped
CI / Clippy Check (push) Failing after 7s
CI / Build (ubuntu-latest) (push) Failing after 8s
Documentation / Build User Guide (push) Successful in 9s
CI / Format Check (push) Failing after 15s
CI / Build (macos-latest) (push) Failing after 20s
CI / Test (macos-latest) (push) Skipped
CI / Test (ubuntu-latest) (push) Skipped
CI / Python Bindings (maturin) (macos-latest) (push) Skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Skipped
CI / WASM Build + Size Check (push) Skipped
CI / Distributed Training Tests (push) Skipped
CI / Build CPU-Only (Explicit) (push) Failing after 1m48s
CI / CI Success (push) Failing after 1s
Documentation / Build API Documentation (push) Failing after 2m29s
Performance Benchmarks / Run Benchmarks (push) Successful in 5m56s
MambaBlock::forward already had a working, tested CUDA dispatch (forward_cuda: cuBLAS matmuls for projections, CPU for the scan). backward() had none — it silently ran entirely CPU-serial on GPU tensors via to_vec()/from_vec() D2H/H2D round-trips. This adds the missing acceleration, mirroring forward_cuda's hybrid split: the four large projection-parameter gradients (in_proj, x_proj, dt_proj, out_proj) now go through batched GPU matmuls; the inherently sequential scan reverse-pass and small per-channel grads stay CPU. Extracted CpuWeights::pull and recompute_forward_cpu out of the old inline per-batch forward-recompute block inside backward() (pure refactor, gradient-checked unchanged by real_selective_scan.rs's existing 6 tests) so CPU backward and the new CUDA backward share identical forward math and can never numerically diverge on it. New CUDA-vs-CPU gradient-check test (mamba_cuda_backward_matches_cpu, #[ignore]-gated, GPU-only) caught a real bug during development: Tensor::contiguous() is a no-op stub in this rtx-tensor version, and cuda_matmul reads raw GPU storage by shape.dims() ignoring strides/offset, so .transpose(..).matmul(..) on a GPU tensor silently computed garbage (80-200x relative error on 3 of 4 accelerated gradients). Fixed by building already-transposed [dim, b*l] buffers on CPU before upload instead of transposing GPU-side. All 9 gradients now match CPU backward within ~2.2e-5 max relative error (tolerance 1e-4). Co-Authored-By: Claude Sonnet 5 <[email protected]> |
||
|
|
4aaa36a57a |
style: cargo fmt --workspace (whitespace/wrapping only, no semantic change)
Whole-workspace rustfmt pass picked up while iterating on Mamba GPU backward work. Verified formatting-only via diff sampling; no logic changed. Co-Authored-By: Claude Sonnet 5 <[email protected]> |
||
|
|
ad6405663f |
fix(streaming): sane DynamicBatchingConfig default; worker lifecycle regression tests
CI / Format Check (push) Failing after 7s
CI / Build (ubuntu-latest) (push) Failing after 7s
CI / Clippy Check (push) Failing after 8s
Documentation / Build API Documentation (push) Failing after 7s
Documentation / Build User Guide (push) Successful in 8s
CI / Build (macos-latest) (push) Failing after 8s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Performance Benchmarks / Run Benchmarks (push) Successful in 26s
CI / Build CPU-Only (Explicit) (push) Failing after 1m17s
CI / CI Success (push) Failing after 0s
The new lifecycle tests caught that the batch-optimizer worker crashed at spawn: DynamicBatchingConfig derived Default (all zeros), and tokio's interval() panics on a zero period. Default is now a usable config (batch 32 in [1,128], step 4, 1ms latency target, 100-sample window, 1s optimization interval, AIMD adaptation). New regression tests in AdaptiveProcessor, EdgeComputingManager, and MonitoringSystem assert that all workers are still alive shortly after start() (catches workers dying at startup) and that stop() completes via the graceful control-channel path, not the 5s abort backstop (catches shutdown hangs). cargo test -p rtx-streaming: 58 lib + 8 integration + 6 aux, all green. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
c83e0fb22d |
fix(streaming): wire worker control planes for real graceful shutdown
CI / Format Check (push) Failing after 7s
CI / Clippy Check (push) Failing after 7s
CI / Build (ubuntu-latest) (push) Failing after 7s
Performance Benchmarks / Run Benchmarks (push) Failing after 9s
CI / Build (macos-latest) (push) Failing after 11s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 11s
CI / CI Success (push) Failing after 1s
Documentation / Build API Documentation (push) Failing after 6s
Documentation / Build User Guide (push) Successful in 7s
Follow-up to
|
||
|
|
a0bf29461b |
fix(streaming): real inference backend wiring and lifecycle fixes; full suite green
Documentation / Build User Guide (push) Successful in 6s
Documentation / Build API Documentation (push) Failing after 6s
CI / Build (macos-latest) (push) Failing after 11s
CI / Format Check (push) Failing after 12s
Performance Benchmarks / Run Benchmarks (push) Successful in 45s
CI / Build (ubuntu-latest) (push) Successful in 2m42s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 2m58s
CI / Clippy Check (push) Failing after 2m59s
CI / CI Success (push) Failing after 0s
- token_generator: backend is now an optional real rtx-inference engine
(RwLock<Option<Arc<InferenceEngine>>>) with ServingTokenizer support;
set_backend/set_tokenizer plumbing through StreamingServer
- connection_manager: ConnectionPool::acquire no longer errors when the
idle cache is full — creates fresh connections up to max_connections
- streaming_server: ServerState::Running on construction; stream_inference
generates one token per step (chunk_size semantics)
- lifecycle bugs surfaced by the newly-compiling integration tests:
* start(): broadcast control-channel send with zero subscribers was
treated as fatal ("channel closed") in RealtimePipeline,
EdgeComputingManager, MonitoringSystem — now tolerated
* stop(): AdaptiveProcessor/EdgeComputingManager/MonitoringSystem
awaited worker interval loops that never exit (test hung 5h) —
workers are now aborted with cancellation-aware join
- integration_tests: removed stale .await on now-synchronous methods
cargo test -p rtx-streaming: 55 lib + 8 integration + 6 aux, all passing.
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
73102b71cf |
feat(transformers): real compute in orchestrator modalities and attention planner
Documentation / Build User Guide (push) Successful in 7s
CI / Build (macos-latest) (push) Failing after 9s
CI / Format Check (push) Failing after 12s
Documentation / Build API Documentation (push) Failing after 14s
Performance Benchmarks / Run Benchmarks (push) Failing after 31s
CI / Clippy Check (push) Failing after 30s
CI / Build (ubuntu-latest) (push) Failing after 36s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 37s
CI / CI Success (push) Failing after 0s
- orchestrator_core: execute_classical is genuine seeded QKV self-attention; execute_flash_attention delegates to rtx_flash_attention::flash_attention_forward (8-head reshape, clear Err on indivisible hidden); execute_hybrid composes the two; execute_edge/execute_distributed return explicit "modality not implemented" errors instead of fake success — which makes the previously-dead fallback_modalities retry loop real. - tensor_core_kernels: AttentionComputationOptimizer::execute dispatches Standard/Online to scaled_dot_product_attention, Flash to rtx-flash-attention, Approximated to an explicit Err (no approximation kernel exists; refuses to compute exact attention under an approximated label). - 10 new always-on tests incl. flash-vs-standard 1e-3 agreement and an Edge->Distributed->Classical fallback end-to-end. - docs/consolidation.md updated: both entries moved from scaffolding/no-op-stub status to real dispatch descriptions. 982 rtx-transformers lib tests pass. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
a755627269 |
feat(jepa): GPU weight re-upload on checkpoint resume
Documentation / Build API Documentation (push) Failing after 5s
CI / Build CPU-Only (Explicit) (push) Failing after 6s
CI / Build (macos-latest) (push) Failing after 9s
Documentation / Build User Guide (push) Successful in 7s
CI / Format Check (push) Failing after 14s
CI / Clippy Check (push) Failing after 23s
CI / Build (ubuntu-latest) (push) Failing after 42s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / CI Success (push) Failing after 0s
Performance Benchmarks / Run Benchmarks (push) Successful in 1m9s
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
GpuViTEncoder gains upload_weights (extracted from construction), cpu_weights_mut, and reupload_weights; JepaTrainerV2 exposes context_encoder_as_any_mut for backend-specific downcasts. The runner resume path now restores checkpoint fields into the GPU encoder's host copy and pushes them back to the device buffers — previously GPU resume restored only the step counter with a warning. If re-upload fails after host restore, the run aborts rather than training on stale device weights. Verified live on the RTX 5060 Ti: train 20 steps -> resume from the .jepa binary with total_steps=30 -> "Resumed from step 20", exactly 10 further steps, eval runs, no warnings. New tests: GPU output changes after host mutation + re-upload; CPU-target re-upload is a no-op Ok. 972 CPU tests / 37 GPU jepa_gpu tests pass. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
ac3f2af06b |
feat(jepa): eval in the training loop, NCCL GPU AllReduce, GPU checkpointing
CI / Format Check (push) Failing after 6s
CI / Build (ubuntu-latest) (push) Failing after 5s
Documentation / Build API Documentation (push) Failing after 7s
Documentation / Build User Guide (push) Successful in 8s
CI / Build (macos-latest) (push) Failing after 11s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Performance Benchmarks / Run Benchmarks (push) Successful in 29s
CI / Clippy Check (push) Failing after 15s
CI / Build CPU-Only (Explicit) (push) Failing after 49s
CI / CI Success (push) Failing after 0s
- Eval: run_jepa_training now runs k-NN (k=5) + linear-probe evaluation every eval_every steps and at the end (deduped when aligned); JepaEvalResult recorded in JepaTrainingSummary (final_knn_acc / final_probe_acc), printed by the CLI, appended as an # eval section to the metrics CSV. Probe set is deterministic LCG synthetic (offset seed, never aliases training batches) or real shard labels when loaded. - NCCL: real GPU-direct AllReduce backend behind the new `nccl` feature (cudarc/nccl, dlopen-based so builds don't need libnccl). NCCL unique id is bootstrapped over the existing TCP rendezvous (master_port+137); data path is htod -> ncclAllReduce(Sum) -> dtoh -> mean. catch_unwind guards cudarc's panic-on-missing-lib so training falls back instead of aborting. Verified for real on the RTX 5060 Ti: single-rank GPU all_reduce identity test passes (26/26 with --features nccl). - GPU checkpointing/eval: JepaTrainerV2::context_encoder_cpu_weights() exposes host-side weights for both CPU and GPU encoders (GpuViTEncoder::cpu_weights); checkpoint save and eval now work for GPU training runs (verified: .jepa binaries written and 2 eval passes during a live GPU CLI run). Resume with a GPU encoder restores the step counter and warns that weight re-upload is not yet implemented rather than silently training on stale weights. 125 runner/distributed/vit tests pass; CLI 8/8; cuda check clean. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
19b6581f9c |
feat(jepa): extended GPU training, data pipeline, integration, and cargo config
Documentation / Build User Guide (push) Successful in 6s
CI / Format Check (push) Failing after 7s
CI / Clippy Check (push) Failing after 7s
CI / Build (ubuntu-latest) (push) Failing after 7s
CI / Build CPU-Only (Explicit) (push) Failing after 7s
CI / Build (macos-latest) (push) Failing after 10s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build API Documentation (push) Failing after 11s
CI / CI Success (push) Failing after 0s
Performance Benchmarks / Run Benchmarks (push) Successful in 26s
- jepa_gpu: remove the bring-up 2-block cap; full-depth GPU-resident ViT verified against a full-depth CPU reference on the RTX 5060 Ti (depth-12 ViT-Tiny max_rel_err <= 6.6e-5). CpuViTEncoder's own hidden min(depth,2) cap removed too — CPU-path callers now get the model they configured. - jepa_distributed: real TCP parameter-server AllReduce backend (rendezvous handshake with world-size/rank validation, length- prefixed f32 payloads, connect/read/accept timeouts, connect retry until deadline so early peers survive rank 0 still computing); jepa_runner wires it for world_size > 1 and fails hard on collective errors. Two-rank loopback training run covered by test. - rtx-jepa-cli (new crate): rtx-jepa binary with train/bench/plan/ validate subcommands driving JepaRunConfig, run_jepa_training, run_jepa_benchmark, and ClusterTrainingPlan (plan --emit-config round-trips through a config serializer). GPU bench on this node: 86k patches/sec vs 1.3k CPU (~64x). - ViTSizeStr::Micro (d=32, depth=2) added as an explicit test/smoke size now that no hidden caps keep full-size configs cheap; heavy tests moved onto it (rtx-transformers suite: 367s -> 5s, and the runner subset had ballooned to 35min at full depth before this). 966 lib tests pass; 35/35 jepa_gpu with cuda; 8/8 CLI tests. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
b6440905e7 |
feat(jepa): gzip-compressed WebDataset shard support
CI / Format Check (push) Failing after 6s
Performance Benchmarks / Run Benchmarks (push) Failing after 7s
CI / Build (ubuntu-latest) (push) Failing after 6s
CI / Clippy Check (push) Failing after 8s
Documentation / Build User Guide (push) Successful in 7s
CI / Build (macos-latest) (push) Failing after 9s
CI / Build CPU-Only (Explicit) (push) Failing after 59s
CI / CI Success (push) Failing after 0s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build API Documentation (push) Failing after 16s
read_webdataset_shard detects the gzip magic bytes (1F 8B, not extension) and decompresses via flate2 before tar parsing; WebDatasetShard::load no longer rejects .tar.gz/.tgz. Round-trip test writes a real gzipped tar and loads it back. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
fdc1432072 |
feat(jepa): full GPU-resident ViT block on CUDA
CI / Build (macos-latest) (push) Failing after 9s
CI / Build CPU-Only (Explicit) (push) Failing after 6s
Documentation / Build User Guide (push) Successful in 6s
Documentation / Build API Documentation (push) Failing after 8s
CI / Format Check (push) Failing after 16s
CI / Clippy Check (push) Failing after 25s
CI / Build (ubuntu-latest) (push) Failing after 58s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / CI Success (push) Failing after 0s
Performance Benchmarks / Run Benchmarks (push) Successful in 4m5s
jepa_gpu.rs rewrite: all GEMMs (QKV, attention scores via a single cuBLAS call with folded 1/sqrt(dk) scale, weighted sum, projections, FFN) plus layernorm/GELU/bias/residual kernels now operate on device-resident CudaSlice buffers; new nvrtc kernels for numerically stable row softmax and head extract/scatter replace the CPU reorder loops. Two host transfers remain per encode(): patch-token upload and final output download. Fallback is now genuine-unavailability only (no device / feature off / kernel compile failure); per-op errors in live GPU mode are hard errors instead of silent per-op CPU downgrades. Parity vs CpuViTEncoder verified on RTX 5060 Ti / CUDA 13.1: max_rel_err <= 3.1e-5 across tiny/Tiny-192 configs (tolerance 1e-3). 34/34 jepa_gpu tests pass with --features cuda; 33/33 CPU-only. CLAUDE.md JEPA "Next" list updated to reflect completed GPU wiring, WebDataset reading, and cluster-plan consumption. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
e080748d88 |
feat(demos,inference): wire simulation demos to real compute; fix embedding lookup and weight-name aliases
GPU Tests / Check GPU Availability (push) Successful in 0s
GPU Tests / Metal Tests (push) Has been skipped
CI / Clippy Check (push) Failing after 7s
Performance Benchmarks / Run Benchmarks (push) Failing after 7s
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 43s
CI / Format Check (push) Failing after 6s
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
CI / Build (ubuntu-latest) (push) Failing after 7s
Documentation / Build User Guide (push) Successful in 8s
CI / Build (macos-latest) (push) Failing after 9s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build API Documentation (push) Failing after 48s
CI / CI Success (push) Failing after 0s
Demos: - rtx-distllm-demo: real rtx-tensor weights per shard, real scaled-dot-product attention forward, metrics measured (Instant) instead of hardcoded constants; network topology remains a documented simulation fed by real tensor byte sizes. - rtx-model-zoo: MockInferenceEngine deleted; RealInferenceEngine loads a tiny real transformer into rtx_inference::InferenceEngine and runs genuine engine.infer per request; domain outputs are explicitly- labeled toy proxies derived from real output tokens. - rtx-inference-profiler: mock models deleted; profiles real matmul/softmax pipelines on rtx-tensor with measured latency/memory. Inference-path bugs the demos surfaced (fixed here): - ForwardPass::apply_embedding misused Tensor::gather for the embedding lookup — gather returns the indices' shape, silently dropping the hidden dim and breaking every downstream broadcast. Now uses the existing Tensor::embedding_lookup ([vocab,hidden] x [batch,seq] -> [batch,seq,hidden]). - Attention weight lookup accepts both self_attn. (HF-LLaMA) and attention. prefixes; final layer norm accepts norm.weight / model.norm.weight / ln_f.weight aliases. - Integration fixture gains the final norm weight; the previously always-failing engine tests now pass (8/8 model_loading_test). End-to-end inference through the real engine now works for the first time — verified via model_zoo_demo producing real forward-pass outputs across all categories. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
733b02cd8b |
feat(inference): concrete EAGLE draft model + real tokenizer at the serving boundary
GPU Tests / Check GPU Availability (push) Successful in 1s
CI / Build (ubuntu-latest) (push) Failing after 6s
CI / Build (macos-latest) (push) Failing after 11s
Documentation / Build User Guide (push) Successful in 7s
CI / Clippy Check (push) Failing after 21s
CI / Format Check (push) Failing after 6s
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 6s
GPU Tests / Metal Tests (push) Has been skipped
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / CI Success (push) Failing after 0s
Performance Benchmarks / Run Benchmarks (push) Successful in 28s
Documentation / Build API Documentation (push) Failing after 25s
EAGLE (rtx-inference/src/eagle.rs, ~610 lines, mirrors medusa.rs conventions): EagleDraftHead autoregressive FFN with Concat/Add/ Attention feature fusion, EagleHeads draft model with draft/ draft_steps (per-step top-k for candidate trees) and teacher-forced training_loss; implements the speculative::EagleDraftModel trait so it plugs into the orchestration layer. 38 unit tests. Tokenizer (rtx-inference/src/tokenizer.rs): ServingTokenizer enum — Vocab (HuggingFace tokenizers, loadable from tokenizer.json) or ByteLevel fallback preserving previous behavior. rtx-serving-api's AppState and rtx-streaming's token generator now encode/decode through it (with_engine_and_tokenizer / set_tokenizer added; existing signatures unchanged). Also fixes two pre-existing compile errors in rtx-streaming (missing import, stray .await) that blocked its lib tests entirely. Tests: rtx-inference 328 pass, rtx-serving-api 193 pass, rtx-streaming 53 pass (2 pre-existing mock-server connection failures unrelated to these changes). Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
0cbfc1a739 |
fix(tests): repair rtx-onnx-codegen build and all pre-existing test failures in rtx-serving-api and rtx-runtime
Documentation / Build API Documentation (push) Failing after 5s
Documentation / Build User Guide (push) Successful in 7s
CI / Format Check (push) Failing after 10s
CI / Build (ubuntu-latest) (push) Failing after 29s
Performance Benchmarks / Run Benchmarks (push) Successful in 31s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / CI Success (push) Failing after 1s
CI / Build (macos-latest) (push) Failing after 9s
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Clippy Check (push) Failing after 34s
CI / Build CPU-Only (Explicit) (push) Failing after 48s
- rtx-onnx-codegen: re-export AttributeValue from ir (private-module import broke the whole crate; remaining errors were knock-ons). - rtx-runtime: gate test_kernel_launch/test_kernel_statistics behind the cuda feature (they need a real CUDA stream; verified passing with --features cuda on the RTX 5060 Ti); non-cuda stream_to_cuda_handle error message now says "not supported" so error-propagation tests are valid in both build modes. - rtx-serving-api (31 failures → 0, 192 pass): per-instance Prometheus registries (macros were silently registering into the global one), kv-cache eviction scoring at microsecond precision + memory_bytes actually reported, #[serde(default)] on cache config for partial TOML, radix-tree capacity/cleanup/prefix-length fixes, sliding-window context-carry fixes, speculative beam-search early-stop fix, CacheValue::is_expired off-by-one, n-gram double-append fix, grammar validation fix, deterministic health status, streaming no-subscriber send no longer treated as an error, websocket messages switched to adjacently-tagged serde (internally-tagged could not serialize the newtype variants at all — the old wire format errored at runtime for those messages; no external consumers existed since the serving layer was mock until this sweep), plus a handful of test-side numerical/formula corrections. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
5f32165184 |
chore(sweep): delete 43 orphaned source files; document SYCL/demo/duplication status
Performance Benchmarks / Run Benchmarks (push) Failing after 7s
GPU Tests / Metal Tests (push) Has been skipped
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 3m32s
CI / Format Check (push) Failing after 5s
CI / Build (macos-latest) (push) Failing after 11s
CI / Build (ubuntu-latest) (push) Failing after 2m34s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build User Guide (push) Successful in 9s
GPU Tests / Check GPU Availability (push) Successful in 0s
CI / Clippy Check (push) Failing after 4m9s
CI / CI Success (push) Failing after 0s
Documentation / Build API Documentation (push) Failing after 4m18s
Deletions (all verified unreferenced by any mod/include/path declaration;
git history preserves them):
- rtx-transformers: entire orphaned curriculum/ split (mod.rs holds the
real inline implementation), non-_simple graph variants, superseded
simmim/jepa_integration files, layers/{sliding_window_attention,
positional_encoding,ssm_state_cache_original}, lib_full/lib_minimal/
error_full/error_minimal, orphaned MoE impls (moe_layer,
moe_integration).
- rtx-distributed/parallel_old.rs; rtx-flash-attention/{core_full,
lib_full}.rs; rtx-compress legacy_distillation + structured_pruner.
- rtx-tensor/tensor_core.rs; rtx-runtime/{cuda_kernel_ops,
cuda_backend_mock}.rs; rtx-memory/{gpu_pool_manager,allocator,
pool_type}.rs; rtx-losses/{lib_minimal,lib_full}.rs.
Docs honesty:
- rtx-backend-sycl marked EXPERIMENTAL SKELETON in crate docs and
CLAUDE.md backend table (all ops return NotImplemented).
- docs/consolidation.md records canonical MoE (layers/mixture_of_experts)
and flash-attention (rtx-flash-attention crate) implementations plus
remaining duplicates to consolidate.
- CLAUDE.md: meta-crate GPU features noted; simulation-only demos named;
serving/streaming mock removal noted.
Verified: cargo check --workspace clean (rtx-onnx-codegen pre-broken at
HEAD, unrelated); lib tests pass for all touched crates (rtx-runtime's 4
failures pre-exist at HEAD).
Co-Authored-By: Claude Fable 5 <[email protected]>
|
||
|
|
1e3c604896 |
feat(meta,jepa): expose GPU features through meta-crates; wire JEPA cluster plan and real shard loading
Meta-crates (Phase 2): - rtx-core / rtx-training / rtx-inference-stack gain cuda and metal features threading into their sub-crates; GPU was previously unreachable through the user-facing bundles. - rtx-training restores rtx-distributed (the hpc-channels blocker is gone) so the advertised DistributedTransformerTrainer resolves; drops the unused rtx-runtime dep. - rtx-transformers drops unused rtx-backend/rtx-backend-cpu deps (stale comment referenced a teacher that never used them). Never-compiled CUDA paths fixed (surfaced by the new feature wiring, verified on RTX 5060 Ti / CUDA 13.1): - rtx-compress build.rs: missing Path/Command/fs imports. - rtx-flash-attention flash_decode_forward: reborrow &mut kernel args. - rtx-transformers: rope kernel include path, cudarc 0.18 Arc<CudaModule>, PushKernelArg imports in jepa_gpu, edition-2024 ref patterns. - rtx-memory: full cudarc 0.18 port (CudaContext, stream-based alloc, DevicePtr accessors, error enum formatting) across gpu_pinning, gpu_transfer, gpu_real, gpu_allocator/arena, gpu_tests. JEPA (Phase 3): - JepaRunConfig::apply_cluster_plan consumes ClusterTrainingPlan (batch size, TP/DP, world size, total steps) so jepa_cluster is no longer standalone dead config; ViTSizeStr::approx_params_m feeds JepaParallelConfig::for_model_and_cluster. - WebDatasetShard::load reads real .tar shards from disk via the existing parser (gzip rejected explicitly); to_in_memory documented as synthetic/test-only. - New image-decode feature actually defines the dep for the previously unreachable cfg(feature = "image-decode") JPEG/PNG decode path. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
64ade03ab9 |
fix(production): wire real inference path through engine, serving, and streaming
- rtx-inference: sample_next_token now copies the actual logits from the forward pass (Tensor::to_vec, last-token slice) instead of sampling from a fabricated all-zero vector; request metrics report measured queue/processing times instead of hardcoded constants. - rtx-serving-api: depends on rtx-inference; /v1/completions dispatches to a shared InferenceEngine (byte-level tokenization until a real tokenizer is threaded through) and returns 503 when no engine is loaded instead of mock text. ServingServer::with_engine attaches one. - rtx-streaming: depends on rtx-inference; generate_tokens delegates to an attached backend engine and errors without one instead of emitting "token_N" placeholders; tokenization is byte-level, not position-mod. - speculative decoding: document the orchestration (speculative/) vs implementation (medusa.rs/lookahead.rs) layering; CLAUDE.md no longer claims a standalone rtx-speculative-decoding crate. Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
522400a72b |
fix(deps): bump candle-core/nn/transformers 0.8->0.11 for CUDA 13.1 build
GPU Tests / Metal Tests (push) Has been skipped
CI / Format Check (push) Failing after 8s
Documentation / Build API Documentation (push) Failing after 8s
Documentation / Build User Guide (push) Successful in 8s
CI / CI Success (push) Failing after 0s
GPU Tests / Check GPU Availability (push) Successful in 0s
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
Performance Benchmarks / Run Benchmarks (push) Failing after 8s
CI / Clippy Check (push) Failing after 8s
CI / Build CPU-Only (Explicit) (push) Failing after 25s
CI / Build (macos-latest) (push) Failing after 32s
CI / Build (ubuntu-latest) (push) Failing after 3m8s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
candle-kernels 0.9.2/0.8.4's compatibility.cuh has a buggy CUDA-version guard ((MAJOR<12 || MINOR<2) && ARCH<750) that misfires on CUDA 13.1, redefining __hmax_nan/__hmin_nan/atomicAdd that 13.1 already provides natively. Fixed upstream in candle-kernels 0.11.0 (pure ARCH<800 gate), so bump the workspace-wide candle pin to pull it in. rtx-csm stays on candle 0.9.1 directly (not the workspace pin) since it shares Tensor types with moshi 0.6.4, which itself pins candle-core 0.9.1 - both candle trees now build cleanly side by side. Also fixes two latent compile issues surfaced by actually building the cuda feature: DType is #[non_exhaustive] with new I16/I32/float8 variants (rtx-candle), and a missing HashMap import gated behind the candle feature (rtx-inference). Co-Authored-By: Claude Sonnet 5 <[email protected]> |
||
|
|
e1b4061c23 |
feat(jepa): extended GPU training, data pipeline, integration, and cargo config
CI / Format Check (push) Failing after 12s
CI / Build (macos-latest) (push) Failing after 12s
CI / Build (ubuntu-latest) (push) Failing after 19s
CI / Distributed Training Tests (push) Has been skipped
CI / Clippy Check (push) Failing after 19s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
Documentation / Build User Guide (push) Successful in 8s
CI / Build CPU-Only (Explicit) (push) Failing after 16s
Documentation / Build API Documentation (push) Failing after 13s
CI / CI Success (push) Failing after 0s
Performance Benchmarks / Run Benchmarks (push) Successful in 43s
Extends jepa_train with distributed launcher, jepa_data with advanced sampling and preprocessing, jepa_gpu with full CUDA kernel wiring, jepa_distributed/runner/metrics/vit with additional training stages. Adds jepa_integration module and project-local cargo config. Co-Authored-By: Claude Sonnet 4.6 <[email protected]> |
||
|
|
b861b3bb2e |
fix(rtx-science): drop unused ndarray-linalg dep
CI / Format Check (push) Failing after 14s
CI / Clippy Check (push) Failing after 1m8s
Documentation / Build User Guide (push) Successful in 14s
Documentation / Build API Documentation (push) Failing after 1m15s
CI / Build (ubuntu-latest) (push) Failing after 1m31s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m0s
CI / Build (macos-latest) (push) Failing after 7m14s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 8m46s
CI / CI Success (push) Failing after 0s
Declared but never referenced; forced openblas-build (no good Apple-Silicon backend) and broke the macOS build. Co-Authored-By: Claude Opus 4.8 <[email protected]> |
||
|
|
63776aa0f2 |
fix(rtx-backend): gate CUDA dev-dep to x86_64-linux so cargo test works on macOS
CI / Build (macos-latest) (push) Failing after 29s
CI / Format Check (push) Failing after 12s
CI / Clippy Check (push) Failing after 1m21s
CI / Build (ubuntu-latest) (push) Failing after 1m22s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build User Guide (push) Successful in 10s
CI / Build CPU-Only (Explicit) (push) Failing after 1m28s
CI / CI Success (push) Failing after 0s
Documentation / Build API Documentation (push) Failing after 43s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m14s
rtx-backend's only build-graph CUDA pull was a [dev-dependencies] entry (rtx-backend-cuda with features=[cuda]) compiled unconditionally, so cargo test --workspace failed on macOS/non-CUDA hosts trying to build cudarc. Gate it to x86_64 Linux (where the CUDA toolkit lives); cargo build was unaffected. Also drop the no-op cuda from rtx-nlg default features (empty placeholder that misleadingly implied CUDA-by-default). Audit: 121/126 workspace crates already gate CUDA correctly (optional + non-default). Co-Authored-By: Claude Opus 4.8 <[email protected]> |
||
|
|
41a844864f |
fix(jepa-vision-bridge): add as_any/as_any_mut to RtxVisionJepaEncoder
CI / Build (macos-latest) (push) Failing after 38s
Documentation / Build API Documentation (push) Failing after 21s
CI / Build CPU-Only (Explicit) (push) Failing after 29s
Performance Benchmarks / Run Benchmarks (push) Successful in 1m57s
CI / Format Check (push) Failing after 22s
CI / Clippy Check (push) Failing after 48s
CI / Build (ubuntu-latest) (push) Failing after 47s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
Documentation / Build User Guide (push) Successful in 7s
CI / CI Success (push) Failing after 1s
Required by JepaEncoder trait update in batch29 (as_any for downcasting). Co-Authored-By: Claude Sonnet 4.6 <[email protected]> |
||
|
|
37db99107f |
feat(batch29): GPU GEMM dispatch, weight serialization, training metrics
CI / Build (ubuntu-latest) (push) Failing after 7s
CI / Format Check (push) Failing after 14s
Documentation / Build User Guide (push) Successful in 10s
CI / Clippy Check (push) Failing after 40s
CI / Build (macos-latest) (push) Failing after 44s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
Documentation / Build API Documentation (push) Failing after 59s
Performance Benchmarks / Run Benchmarks (push) Successful in 2m23s
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 3m22s
CI / CI Success (push) Failing after 0s
Batch 29a — GpuViTEncoder cudarc round-trip + 6 new tests (18 total): - GpuWeightBuffers: CudaSlice<f32> for patch_embed/proj_w/per-block qkv+ffn - cuda() constructor: CudaContext::new() + stream.clone_htod() weight upload - encode(): GPU htod→dtoh round-trip when context+weights present; CPU fallback - warmup(): touches proj_w buffer via dtoh; has_gpu_weights(), gpu_buffer_count() - JepaTrainerV2 encoder field visibility: ViTBlock+CpuViTEncoder pub(crate) - JepaEncoder trait: as_any()/as_any_mut() for downcasting; impl on all encoders Batch 29b — Binary weight serialization (jepa_checkpoint.rs, 18 tests): - Format: b"JEPA" magic + version u32 + fields + step u64 + checksum u32 - serialize/deserialize_checkpoint(): pure binary, no deps - save/load_checkpoint(): file I/O wrappers with CheckpointError enum - encoder_to_fields() / apply_fields_to_encoder(): CpuViTEncoder ↔ WeightField - JepaTrainerV2::context_encoder_as_cpu[_mut]() via Any downcast - JepaCheckpoint::save_with_trainer(): writes JSON summary + .jepa binary - run_jepa_training(): auto-resume from config.resume_from checkpoint path Batch 29c — Training metrics logger (jepa_metrics.rs, 20 tests + 3 runner): - StepMetrics, WindowMetrics, TrainingSummaryReport types - JepaMetricsLogger: EMA loss (α=0.02), loss_trend() linear regression, eta_seconds(), progress_line() with [====>.....] bar and ETA - to_csv() / save_csv() export; training_summary() → TrainingSummaryReport - run_jepa_training() wired: delegates all logging to metrics_logger.progress_line() - JepaRunConfig: +metrics_csv_path (saved at end if set) Co-Authored-By: Claude Sonnet 4.6 <[email protected]> |
||
|
|
0b06c0fa81 |
feat(batch28): GpuViTEncoder, distributed grad sync, eval harness
Performance Benchmarks / Run Benchmarks (push) Failing after 7s
CI / Format Check (push) Failing after 11s
Documentation / Build User Guide (push) Successful in 11s
CI / Build (macos-latest) (push) Failing after 29s
CI / Build (ubuntu-latest) (push) Failing after 52s
CI / Clippy Check (push) Failing after 54s
Documentation / Build API Documentation (push) Failing after 52s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
CI / Build CPU-Only (Explicit) (push) Failing after 3m22s
CI / CI Success (push) Failing after 0s
Gap 1 — GpuViTEncoder + encoder-agnostic JepaTrainerV2 (jepa_gpu.rs, 12 tests):
- ExecutionTarget enum (Cpu | Cuda{device_id}); GpuViTEncoder wraps CpuViTEncoder
- cuda feature: Arc<CudaDevice> + try_allocate_gpu_buffer() via cudarc
- no-cuda: graceful Cpu fallback with correct shapes
- JepaTrainerV2 now holds Box<dyn JepaEncoder> + EmaTargetEncoderDyn
- new_with_encoder() constructor; JepaTrainerV2::new() backward-compatible
- JepaEncoder::l2_normalize gets `where Self: Sized` for dyn-compatibility
- 46 existing jepa_vit tests preserved (zero regressions)
Gap 4 — Distributed gradient sync (jepa_distributed.rs, 15 tests):
- JepaGradSync: single_process / simulated(world_size, rank) / nccl(...)
- sync_gradients(): noop at world_size=1; divides grads by world_size (simulated)
- effective_batch_size(), is_primary(), barrier() stubs
- JepaRunConfig: +world_size/rank/master_addr/master_port fields + TOML parser
- run_jepa_training() wired: creates JepaGradSync, syncs after each step,
gates logging+checkpointing on is_primary(); summary carries world_size + eff_batch
Gap 6 — JEPA eval harness (jepa_eval.rs + examples/jepa_eval.rs, 15 tests):
- JepaEvalConfig: feature_dim, num_classes, linear probe + kNN params, seed, mode
- EvalMode: LinearProbe / KNN / Both
- run_eval_suite(): LCG-generated L2-normalised features → JepaEvaluator dispatch
- load_features_txt / load_labels_txt / save_eval_csv (stdlib only)
- EvalSuiteResult::summary() and to_csv_row()
- examples/jepa_eval.rs: --mode/--dim/--classes/--train/--test/--epochs/--lr/--k
--seed/--features/--labels/--test-features/--test-labels/--output CLI flags
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
||
|
|
f487196367 |
feat(batch27): JEPA ViT bridge, WebDataset shard reading, training loop
CI / Format Check (push) Failing after 11s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
Documentation / Build User Guide (push) Successful in 9s
CI / Build CPU-Only (Explicit) (push) Failing after 1m10s
CI / CI Success (push) Failing after 0s
Documentation / Build API Documentation (push) Failing after 40s
Performance Benchmarks / Run Benchmarks (push) Successful in 7m53s
CI / Build (macos-latest) (push) Failing after 30s
CI / Build (ubuntu-latest) (push) Failing after 48s
CI / Distributed Training Tests (push) Has been skipped
CI / Clippy Check (push) Failing after 52s
Gap 2 — rtx-vision ViT bridge (jepa_vision_bridge.rs, 8 tests): - ViT::forward_features(): patch reps without classification head - ViT::encode_patch_indices(): shape-correct placeholder for GPU dispatch - RtxVisionJepaEncoder implementing JepaEncoder (vision-bridge feature) - From<&ViTConfig> for JepaViTConfig config conversion - rtx-vision added as optional dep; vision-bridge feature gate Gap 3 — WebDataset tar-shard reading (jepa_data.rs, +12 tests, 47 total): - parse_tar_bytes(): pure stdlib tar parser (512-byte block format) - read_webdataset_shard(): file reader with ShardLoadStats timing - WebDatasetRecord: key, image_bytes, label, extension - ShuffleBuffer: fixed-capacity reservoir sampling via LCG PRNG - JepaDataPipeline::from_filesystem(): validates paths, loads shards, builds pipeline Gap 5 — Training loop runner (jepa_runner.rs + examples/jepa_train.rs, 15 tests): - JepaRunConfig with TOML-style key=value parser - run_jepa_training(): full training loop (JepaTrainerV2, cosine LR, checkpointing) - JepaCheckpoint::save() writes JSON summary; load() stub - examples/jepa_train.rs: --config/--size/--steps/--dry-run CLI flags Co-Authored-By: Claude Sonnet 4.6 <[email protected]> |
||
|
|
e8a2036db4 |
fix(ci,rtx-tensor): resolve clippy --all-features intel-mkl conflict; gate MKL to x86_64-linux
CI / Build (macos-latest) (push) Failing after 26s
CI / Format Check (push) Failing after 10s
CI / Clippy Check (push) Failing after 19s
Performance Benchmarks / Run Benchmarks (push) Successful in 28s
CI / Build (ubuntu-latest) (push) Failing after 15s
CI / Test (macos-latest) (push) Has been skipped
CI / Test (ubuntu-latest) (push) Has been skipped
CI / Python Bindings (maturin) (macos-latest) (push) Has been skipped
CI / Python Bindings (maturin) (ubuntu-latest) (push) Has been skipped
CI / WASM Build + Size Check (push) Has been skipped
CI / Distributed Training Tests (push) Has been skipped
GPU Tests / Check GPU Availability (push) Successful in 1s
GPU Tests / CUDA Tests (11.8) (push) Has been skipped
GPU Tests / CUDA Tests (12.1) (push) Has been skipped
Documentation / Build User Guide (push) Successful in 6s
Documentation / Build API Documentation (push) Failing after 50s
CI / Build CPU-Only (Explicit) (push) Failing after 1m0s
GPU Tests / Metal Tests (push) Has been skipped
CI / CI Success (push) Failing after 0s
clippy --all-features enabled both rtx-tensor/mkl (intel-mkl-src mkl-static-lp64-seq) and rtx-csm/candle mkl (mkl-static-lp64-iomp) -> two conflicting intel-mkl-src link configs -> E0428 'MKL_CONFIG defined multiple times'. - clippy: drop --all-features (lint default features; --all-features is unsound for a multi-platform, mutually-exclusive-backend workspace). - rtx-tensor: gate intel-mkl-src to cfg(all(target_os=linux, target_arch=x86_64)) so mkl is never pulled on macOS/arm. Co-Authored-By: Claude Opus 4.8 <[email protected]> |