52fd40f8f268e66b1de419bfa215d21f2ea746b8
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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]>
|
||
|
|
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]>
|