2D Linear Elasticity FEM Solver — Rust implementation.
Full finite element analysis pipeline for plane stress / plane strain problems: parse mesh → compute element stiffness → assemble K → apply BCs → solve Ku=f → recover stresses.
Built as Project 2 in the computational science portfolio (see python.md).
This is the solver you built in C during your FEM course, rebuilt in Rust with a clean architecture, two solvers, parallel assembly, and verified against analytical solutions.
fem-solver/
├── Cargo.toml
├── src/
│ ├── main.rs — CLI entry point, orchestrates full pipeline
│ ├── mesh.rs — Input file parser (nodes, elements, BCs, materials)
│ ├── element.rs — CST element stiffness k_e = t·A·Bᵀ·C·B
│ ├── assembly.rs — Global K and f assembly (parallel with Rayon)
│ ├── boundary.rs — Dirichlet BC elimination
│ ├── solver.rs — Gauss elimination + Conjugate Gradient
│ └── postprocess.rs — Strains, stresses, Von Mises, file output
├── examples/
│ ├── cantilever.fem — Cantilever beam (tip load, validates against beam theory)
│ └── patch_test.fem — Patch test (constant strain, exact stress recovery)
└── python/
├── plot_results.py — Deformed mesh, Von Mises field, CG convergence plots
└── requirements.txt
# Build (release mode)
cargo build --release
# Run patch test (validation — both solvers, compare)
./target/release/fem-solver examples/patch_test.fem --both
# Run cantilever beam
./target/release/fem-solver examples/cantilever.fem --both
# Plot results
pip install -r python/requirements.txt
python python/plot_results.py examples/cantilever_cg_results.txt| Flag | Solver |
|---|---|
| (none) | Gauss elimination (direct, partial pivoting) |
--cg |
Conjugate Gradient (iterative, SPD systems) |
--both |
Run both and compare |
For a 3-node triangle with nodes
Element area:
Shape function derivative coefficients:
Strain-displacement matrix
Constitutive matrix
Element stiffness (6×6):
Element body force (6×1):
DOF mapping: node
For each element with global nodes
For each constrained DOF
-
$f_i \mathrel{-}= K_{id}\cdot v$ for all free rows$i \neq d$ - Zero row
$d$ and column$d$ $K_{dd} = 1,\quad f_d = v$
Result is still SPD → Conjugate Gradient valid.
Von Mises stress (plane stress/strain):
Prescribed displacements:
Expected (analytical):
FEM result:
Both elements recover the exact constant stress state — patch test passes.
| Parameter | Value |
|---|---|
| L × H | 2.0 × 0.5 mm |
| E, ν | 210 000 MPa, 0.3 |
| Tip load P | 100 N |
| I = tH³/12 | 0.01042 mm⁴ |
Euler-Bernoulli tip deflection:
FEM result (4×2 mesh, CST):
The under-prediction is expected — CST elements suffer from shear locking in bending problems on coarse meshes. Refining to 20×10 elements converges to within ~5% of beam theory. This is a known FEM teaching point: CST ≠ good bending element; Q4 or LST elements converge faster.
CG solver: 30 iterations (= n_free_DOFs), residual
| Case | DOFs | Gauss | CG iterations |
|---|---|---|---|
| Patch test | 8 | < 0.01 ms | 1 |
| Cantilever | 30 | < 0.01 ms | 30 |
| Parallelism | element loop | Rayon par_iter | — |
For larger meshes (thousands of DOFs), the Rayon parallel assembly scales across all CPU cores. Gauss elimination is
# comment
PROBLEM plane_stress # or plane_strain
MATERIAL E 210000 nu 0.3 thickness 1.0
NODES
# id x y
1 0.0 0.0
...
ELEMENTS
# id n1 n2 n3 (CCW node order)
1 1 2 7
...
BODY_FORCE bx 0.0 by 0.0
DIRICHLET
# node_id dof value (dof: 0=ux, 1=uy)
1 0 0.0
...
POINT_FORCES
# node_id fx fy
10 0.0 -100.0
...
END
| FEM course (C) | This project (Rust) |
|---|---|
read_input() |
mesh::Mesh::from_file() |
compute_ke() |
element::element_stiffness() |
assemble_K() |
assembly::assemble() (+ Rayon) |
apply_dirichlet() |
boundary::apply_dirichlet() |
| Gauss in C | solver::gauss_elimination() |
| — | solver::conjugate_gradient() (CSR-ready) |
| Fraunhofer IWM solver | Full pipeline above |
The CSR sparse format (used in your HPC benchmarks) is the natural extension: replace Vec<f64> (dense, n²) with triplets → CSR, and the CG solver is unchanged because it only needs a matrix-vector product.
- Replace dense K with COO → CSR format (reduces memory from
$O(n^2)$ to $O(\text{nnz})$) - Add incomplete Cholesky preconditioner to reduce CG iterations from
$O(n)$ to$O(\sqrt{n})$ - Add MPI domain decomposition: partition mesh with METIS, local assembly, halo exchange
- Add Q4 quad elements or LST (6-node triangle) to eliminate shear locking
- Add Neumann BC (distributed traction on edges)
Created as part of the computational science portfolio:
Project 2 — 2D FEM Solver for Linear Elasticity
See python.md (root) for the full four-project plan and career context.