Commit Graph
5 Commits
Author SHA1 Message Date
Omar SobhandClaude Fable 5 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]>
2026-08-20 00:43:32 -07:00
Omar SobhandClaude Fable 5 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]>
2026-08-19 18:52:50 -07:00
Omar SobhandClaude Opus 5 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]>
2026-08-19 08:21:58 -07:00
osobhandClaude Opus 4.6 02d382d5f6 style: apply rustfmt across all crates and demos
Consistent formatting pass: line wrapping, import sorting, trailing
whitespace removal, let-chain indentation, merged derive attributes,
and unsafe block reformatting.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
2026-04-12 07:01:58 -07:00
redclawsystems 4d88dc0584 Initial commit 2026-03-04 00:08:42 +00:00