forked from 1b-agent/fieldcraft-upstream
Implicit solver: fem kernels (tet4/10, hex8, hex20), sparse Cholesky, block Lanczos, solve.* commands (M4) (#23)
* Renumber the layer table for solver crates: fem at L1, solver at L2, fsi at L3 L0 model -> L1 geometry, mesh, fem, decks, render -> L2 solver (explicit, lbm later) -> L3 fsi (later) -> L4 doc -> L5 io -> L6 engine -> L7 ui-egui, mcp -> apps. UI_MIN_LAYER moves to 7, the testkit sits above it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * modelcraft-fem: element kernels for tet4, tet10, hex8 (full, incompatible modes), hex20 (full, reduced) Shape functions, Gauss and conical-product quadrature, stiffness, consistent and HRZ-lumped mass, body forces, consistent pressure loads on faces, integration-point stresses and their least-squares extrapolation to nodes, isotropic and orthotropic elasticity. The element table is one row per kind, so wedges, shells and beams are added locally. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * modelcraft-solver: linear static and frequency analysis with an analytic verification suite Assembly from the resolved model on the node graph, boundary conditions by elimination, consistent pressure, gravity and body-force loads, nested-dissection ordering, sparse up-looking Cholesky with a factor-size cap, reactions, integration-point and nodal-averaged stresses, von Mises; shift-invert block Lanczos with full reorthogonalization for natural modes, participation and effective mass. ADR 0001 records the own-linear-algebra decision (determinism, wasm). Verified against closed forms: displacement and traction patch tests for every element, cantilever tip deflection (Timoshenko) with convergence rates, Lamé cylinder, Kirsch hole (Kt -> 3), cantilever and free-free beam frequencies with six rigid-body modes. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Engine: solve.static, solve.frequency and solve.probe; results kept in the session Results are stored per step, restored on a failed command and cleared when the model changes. Caps (degrees of freedom, factor entries, Lanczos vectors) may only be lowered; hostile parameters are tested against a solvable session. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: implicit solver architecture, roadmap M4, parity and references Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * Simplify the solver: shared face integration, block assembly, cached extrapolation - model: one face integrator (nodal::face_normal_weights) for tractions and pressures - fem: mid-side tables from ElementKind::edges, orthotropic via inverse3, symmetric accumulation without a symmetrize pass, incompatible-mode recovery without K_uu, model's coordinate check, dead table rows removed - solver: one pattern search per node pair (block, scalar and diagonal adds), extrapolation built once per element type, reactions from the prescribed rows only, matrices dropped after restriction, the free-body shift keyed on the factorization error, step selection in the solver, Error::Element naming the element - engine: the solver owns the default step and the shift check; the model comparison runs once Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm * docs: results are stamped with the session revision Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --------- Co-authored-by: jyviko <[email protected]> Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
33 files changed
+4559
-53
No files matched your search
@@ -26,8 +26,19 @@ predicates that `robust` lacks). `robust` (georust, MIT OR Apache-2.0) and `num-
|
||||
`num-rational` / `num-traits` (MIT OR Apache-2.0) are dev-dependencies only: differential test
|
||||
oracles, never linked into ModelCraft.
|
||||
|
||||
**Linear algebra:** to be decided in the solver task, among permissively licensed pure-Rust
|
||||
crates (for example `faer`, MIT). Record the choice here.
|
||||
**Linear algebra: our own.** *Decided 2026-10-13 (implicit solver task):* `modelcraft-solver`
|
||||
has its own sparse symmetric storage, nested-dissection ordering (George 1973, by coordinate
|
||||
bisection), up-looking sparse Cholesky (Davis 2006, elimination trees per Liu 1990) and
|
||||
shift-invert block Lanczos with full reorthogonalization (Ericsson–Ruhe 1980, Grimes–Lewis–Simon
|
||||
1994) on a Householder + implicit-QR dense eigensolver (Golub–Van Loan). `faer` (MIT) was the
|
||||
alternative and is faster on large problems, but it selects SIMD kernels by CPU feature at run
|
||||
time (AVX2, AVX-512, NEON), which changes floating-point reduction order between machines and
|
||||
breaks the bit-for-bit determinism rule; it is also a large dependency tree for the browser
|
||||
build. Our code is sequential with a fixed operation order, `unsafe`-free and wasm-safe, and its
|
||||
factor size is known (and capped) before any value is computed. Cost if this is wrong: large
|
||||
models (beyond a few hundred thousand equations) factor slower than they could; the remedy is a
|
||||
supernodal factorization of our own, or `faer` behind the same `Factor` interface with a stated
|
||||
tolerance instead of bit-identity, as the GPU exception already does.
|
||||
|
||||
**Allowed:** MIT, BSD-2/3, Apache-2.0, ISC, Zlib, Unicode, MPL-2.0 (as an unmodified dependency),
|
||||
CC0 and public domain.
|
||||
|
||||
+41
-6
@@ -21,18 +21,20 @@ crates in strictly lower layers.
|
||||
| L0 | `modelcraft-model` | Solver-neutral FE model: nodes and elements by label, their geometry tags, sets, materials, sections, couplings, BCs, loads and steps, the model check and the resolved view the writers read. Knows no file format and no geometry type. | started |
|
||||
| L1 | `modelcraft-geometry` | The only door to SolidCraft: opens `.solidcraft` designs (rebuilt from their timeline, bodies with persistent face names), B-rep bodies, measures, tessellation into a face-tagged `SurfaceMesh`; face-tagged 3MF files read into the same type without the kernel (docs/formats/tagged-mesh.md). No SolidCraft type in its API. | started |
|
||||
| L1 | `modelcraft-mesh` | Surface preparation (weld, watertightness, feature edges), robust predicates, Delaunay tetrahedralization and refinement, Voronoi-based optimization, hex meshing, quality metrics. | started |
|
||||
| L1 | `modelcraft-solver` | Element formulations, assembly, sparse linear static and modal solution. | planned |
|
||||
| L1 | `modelcraft-fem` | Element kernels shared by every structural solver: the element table (tet4, tet10, hex8 full and incompatible modes, hex20 full and reduced), shape functions, quadrature, element stiffness, consistent and lumped mass, body and pressure loads, stresses and their extrapolation, isotropic and orthotropic elasticity. Pure functions, no solver loop. | started |
|
||||
| L1 | `modelcraft-decks` | Abaqus input, Nastran bulk data and LS-DYNA keyword readers and writers, to and from `model`. Text out, no file system; `deck.write` saves it. | started |
|
||||
| L1 | `modelcraft-render` | Display data without a GPU dependency: the visible faces, element edges and nodes of a model, the orbit camera, a CPU rasterizer for headless snapshots; contour maps later. | started |
|
||||
| L2 | `modelcraft-doc` | The document: geometry, mesh, model, results, history. | planned |
|
||||
| L3 | `modelcraft-io` | `.modelcraft` files (docs/formats/modelcraft.md): text model definition, binary mesh, geometry references with content hashes, the journal; atomic saves; autosave storage for crash recovery. Bytes in, bytes out; the file system only in `fs` and `recovery`. Result files later. | started |
|
||||
| L4 | `modelcraft-engine` | Commands (`CommandSpec`), `Session::execute` with rollback and the panic guard, scripts. | started |
|
||||
| L5 | `modelcraft-ui-egui`, `modelcraft-mcp` | Desktop UI (egui + wgpu viewport, model tree, commands, status bar) and control channel requests (docs/control-protocol.md); MCP server. | ui started |
|
||||
| L2 | `modelcraft-solver` | Implicit solver: assembly from the resolved model, boundary conditions, sparse direct solution, linear static and modal analysis, stresses and reactions. The explicit (`modelcraft-explicit`) and lattice Boltzmann (`modelcraft-lbm`) solvers join this layer. | started |
|
||||
| L3 | `modelcraft-fsi` | Fluid–structure coupling between the L2 solvers (later). | planned |
|
||||
| L4 | `modelcraft-doc` | The document: geometry, mesh, model, results, history. | planned |
|
||||
| L5 | `modelcraft-io` | `.modelcraft` files (docs/formats/modelcraft.md): text model definition, binary mesh, geometry references with content hashes, the journal; atomic saves; autosave storage for crash recovery. Bytes in, bytes out; the file system only in `fs` and `recovery`. Result files later. | started |
|
||||
| L6 | `modelcraft-engine` | Commands (`CommandSpec`), `Session::execute` with rollback and the panic guard, scripts. | started |
|
||||
| L7 | `modelcraft-ui-egui`, `modelcraft-mcp` | Desktop UI (egui + wgpu viewport, model tree, commands, status bar) and control channel requests (docs/control-protocol.md); MCP server. | ui started |
|
||||
| testkit | `modelcraft-testkit` | Test tooling, a dev-dependency only: the meshing test corpus (`tests/corpus/*/recipe.json`, analytic shapes) and its runner (`cargo xtask corpus`). | started |
|
||||
| apps | `modelcraft`, `modelcraft-cli`, `modelcraft-web` | Desktop, command line, browser. | desktop, cli started |
|
||||
|
||||
Rules beyond the layer order:
|
||||
- Nothing below L5 uses egui, eframe, winit, wgpu or rfd.
|
||||
- Nothing below L7 uses egui, eframe, winit, wgpu or rfd.
|
||||
- Only `modelcraft-geometry` uses `solidcraft-*`, pinned by rev in the workspace `Cargo.toml`.
|
||||
SolidCraft's `[patch.crates-io]` (its fixed truck crates) does not reach dependents, so the
|
||||
workspace repeats it from the same rev; bump both together. The same goes for SolidCraft's
|
||||
@@ -120,6 +122,39 @@ element names, cards and keywords):
|
||||
- **Files.** A model deserializes by replaying its contents through the same checked methods the
|
||||
commands use, so a file cannot hold what commands would refuse.
|
||||
|
||||
## Implicit solver
|
||||
|
||||
`modelcraft-solver` solves a model's linear static and frequency steps (`solve.static`,
|
||||
`solve.frequency`; `solve.probe` reads the stored results). Methods and papers are cited in the
|
||||
module docs; ADR 0001 records why the linear algebra is our own.
|
||||
|
||||
1. **System.** `Model::resolve()`; each solid section's elements take their material's
|
||||
elasticity matrix and the section's formulation (`modelcraft_fem::element::ELEMENT_TYPES`, one
|
||||
row per element kind). Couplings, reference points, moments, shells and beams return "not
|
||||
supported yet". The step's boundary conditions prescribe translations (rotations do not exist
|
||||
on solid nodes); its loads become a load vector: forces and tractions from
|
||||
`Resolved::nodal_loads`, pressure as consistent face loads, gravity and body forces through the
|
||||
element shape functions.
|
||||
2. **Assembly** on the node graph (3 × 3 blocks, elements in label order, so sums are
|
||||
reproducible bit for bit).
|
||||
3. **Ordering and elimination.** Nested dissection of the nodes by coordinate bisection; free
|
||||
degrees of freedom numbered in that order; prescribed values moved to the right-hand side (no
|
||||
penalty).
|
||||
4. **Static solution.** Up-looking sparse Cholesky (the factor size is computed and capped before
|
||||
any value), reactions K u − f, integration-point stresses extrapolated to the nodes and
|
||||
averaged, von Mises. A zero pivot names the node and direction that can move freely.
|
||||
5. **Frequency.** Shift-invert block Lanczos (block 6, full reorthogonalization) on
|
||||
K − σM, σ = 0 for a supported structure and slightly negative for a free one, so rigid-body
|
||||
modes come out at zero; mass-normalized shapes, participation factors and effective masses.
|
||||
6. **Results** stay in the session per step, stamped with the session revision they were solved
|
||||
at; `Session::result` hands out only those of the current revision, so an edit makes them
|
||||
stale and undoing back to the solved state makes them current again.
|
||||
|
||||
Verification (`crates/solver/tests/verification.rs`, analytic only): displacement and traction
|
||||
patch tests for every element and formulation (exact to round-off), cantilever tip deflection
|
||||
against Timoshenko with convergence rates of the linear elements, Lamé's cylinder, Kirsch's
|
||||
plate with a hole (Kt → 3), cantilever and free–free beam frequencies with six rigid-body modes.
|
||||
|
||||
## Commands
|
||||
|
||||
Every user-visible action is a `CommandSpec` in `crates/engine/src/cmd/<area>.rs` with a JSON
|
||||
|
||||
+2
-2
@@ -60,8 +60,8 @@ products are run, no documentation text is copied). Status: **done**, **started*
|
||||
| Decks | Nastran bulk data writer (`deck.write`, SOL 101 or 103 per deck; reports what Nastran cannot express) | M3 | | done |
|
||||
| Decks | LS-DYNA keyword writer (implicit; explicit in M8) | M3 | | done (implicit static and eigenvalue; beam sections planned) |
|
||||
| Decks | Readers keeping unknown keywords | M9 | | planned |
|
||||
| Solve | Own linear static and modal solver, verified against analytic solutions | M4 | yes | planned |
|
||||
| Results | Deformed shape, contours, mode shapes, probes, reaction sums | M4 | | planned |
|
||||
| Solve | Own linear static and modal solver, verified against analytic solutions | M4 | yes | started (solid elements: tet4, tet10, hex8, hex20) |
|
||||
| Results | Deformed shape, contours, mode shapes, probes, reaction sums | M4 | | started (results in the session, `solve.probe`, reaction sums; display planned) |
|
||||
| Results | XY and path plots, cuts, display groups, free-body forces, animation | M9 | | planned |
|
||||
| Results | Readers for public result formats (Nastran OP2, LS-DYNA d3plot, Abaqus `.fil`) | M9 | | planned |
|
||||
| Results | Mesh convergence studies | M9 | | planned |
|
||||
|
||||
@@ -953,3 +953,30 @@ the better pairing — this is why FSI should support both structure solvers.
|
||||
tagged as "benchmark", kept separate from the analytic suite).
|
||||
8. **Quad shell meshing is missing from the roadmap.** X5 needs quad-dominant surface meshes; without them shells
|
||||
run on tri3 (BLT has a triangular variant, less accurate). Flag for the roadmap.
|
||||
|
||||
## Part G: Implicit solver (M4), as implemented
|
||||
|
||||
The papers and books `modelcraft-fem` and `modelcraft-solver` are written from (cited again in
|
||||
the module docs):
|
||||
|
||||
- Elements: O. C. Zienkiewicz, R. L. Taylor, J. Z. Zhu, *The Finite Element Method: Its Basis
|
||||
and Fundamentals*, 7th ed., 2013; T. J. R. Hughes, *The Finite Element Method*, Dover 2000.
|
||||
- Incompatible modes: Wilson, Taylor, Doherty, Ghaboussi 1973; R. L. Taylor, P. J. Beresford,
|
||||
E. L. Wilson, IJNME 10(6):1211–1219, 1976 (the det J₀/det J correction that passes the patch
|
||||
test).
|
||||
- Tetrahedron quadrature: A. H. Stroud, *Approximate Calculation of Multiple Integrals*, 1971
|
||||
(conical product rules).
|
||||
- Mass lumping: E. Hinton, T. Rock, O. C. Zienkiewicz, Earthquake Eng. Struct. Dyn.
|
||||
4(3):245–249, 1976.
|
||||
- Stress extrapolation: E. Hinton, J. S. Campbell, IJNME 8(3):461–480, 1974.
|
||||
- Ordering: A. George, SIAM J. Numer. Anal. 10(2):345–363, 1973; H. D. Simon, Computing Systems
|
||||
in Engineering 2:135–148, 1991.
|
||||
- Sparse Cholesky: T. A. Davis, *Direct Methods for Sparse Linear Systems*, SIAM 2006; J. W. H.
|
||||
Liu, SIAM J. Matrix Anal. Appl. 11(1):134–172, 1990.
|
||||
- Eigenvalues: T. Ericsson, A. Ruhe, Math. Comp. 35(152):1251–1268, 1980; R. G. Grimes, J. G.
|
||||
Lewis, H. D. Simon, SIAM J. Matrix Anal. Appl. 15(1):228–272, 1994; B. N. Parlett, *The
|
||||
Symmetric Eigenvalue Problem*, SIAM 1998; G. H. Golub, C. F. Van Loan, *Matrix Computations*,
|
||||
4th ed., 2013.
|
||||
- Verification: R. H. MacNeal, R. L. Harder, *A proposed standard set of problems to test finite
|
||||
element accuracy*, Finite Elem. Anal. Des. 1(1):3–20, 1985 (patch tests); Lamé, Kirsch,
|
||||
Timoshenko and Euler–Bernoulli closed forms.
|
||||
Reference in new issue
Block a user