FEM Chain Workflow (CalculiX)
Overview
End-to-end structural FEM pipeline: gmsh geometry → INP file → CalculiX solve → stress/displacement extraction.
Pipeline Steps
- Create geometry — gmsh OCC kernel (plate-with-hole, STEP import, etc.)
- Define analysis — material, BCs, loads → INP file via INPWriter
- Solve — CalculiX
ccx subprocess
- Extract results — parse
.frd (nodal fields) and .dat (reactions)
Quick Start: Plate-with-Hole Validation
from digitalmodel.solvers.calculix.fem_chain import FEMChain
chain = FEMChain()
result = chain.run_plate_validation(sigma_applied=100.0)
print(f"Kt = {result['kt']:.3f}") # ~3.0 within 5%
Custom Analysis
from pathlib import Path
from digitalmodel.solvers.calculix.fem_chain import FEMChain
chain = FEMChain(work_dir=Path("/tmp/my_fem"))
# 1. Create geometry (quarter-symmetry plate with hole)
stats = chain.create_plate_with_hole(
plate_w=200.0, plate_h=200.0, hole_r=10.0,
thickness=1.0, element_size=5.0,
)
# 2. Setup analysis
chain.setup_analysis(
material={"name": "STEEL", "E": 210000.0, "nu": 0.3},
loads=[{
"type": "cload", "node_set": "LOAD",
"dof": 1, "magnitude": 100.0, "direction": (1, 0, 0),
}],
boundary_conditions=[
{"node_set": "SYM_X", "dof_start": 1, "dof_end": 1},
{"node_set": "SYM_Y", "dof_start": 2, "dof_end": 2},
{"node_set": "FIX_Z", "dof_start": 3, "dof_end": 3},
],
)
# 3. Solve
status = chain.solve()
assert status["success"]
# 4. Results
results = chain.extract_results()
print(f"Max von Mises: {results['max_von_mises']:.1f} MPa")
print(f"Max displacement: {results['max_displacement']:.6f} mm")
Key Classes
| Class |
Module |
Purpose |
FEMChain |
solvers.calculix.fem_chain |
End-to-end orchestrator |
INPWriter |
solvers.calculix.inp_writer |
Mesh → INP file conversion |
CalculiXResultParser |
solvers.calculix.result_parser |
.frd/.dat parsing |
GMSHMeshGenerator |
solvers.gmsh_meshing.mesh_generator |
STEP import + meshing |
Prerequisites
gmsh Python package (pip install gmsh)
ccx binary on PATH (CalculiX solver)
- Check availability:
from digitalmodel.solvers.calculix.fem_chain import is_calculix_available
Node Sets (Plate-with-Hole)
| Set |
Description |
SYM_X |
Nodes on x=0 symmetry plane |
SYM_Y |
Nodes on y=0 symmetry plane |
FIX_Z |
Nodes on z=0 face (out-of-plane constraint) |
LOAD |
Nodes on far edge (x=W/2) for applied traction |
Validated Results
- Plate-with-hole Kt within 5% of theoretical 3.0 (d/W < 0.3)
- Quarter-symmetry model with W/d > 5
1---2name: freecad-automation-fem-chain-workflow3description: Sub-skill of freecad-automation: CalculiX FEM analysis chain — geometry creation via gmsh, INP export, ccx solve, and result extraction.4---56# FEM Chain Workflow (CalculiX)78## Overview910End-to-end structural FEM pipeline: gmsh geometry → INP file → CalculiX solve → stress/displacement extraction.1112## Pipeline Steps13141. **Create geometry** — gmsh OCC kernel (plate-with-hole, STEP import, etc.)152. **Define analysis** — material, BCs, loads → INP file via INPWriter163. **Solve** — CalculiX `ccx` subprocess174. **Extract results** — parse `.frd` (nodal fields) and `.dat` (reactions)1819## Quick Start: Plate-with-Hole Validation2021```python22from digitalmodel.solvers.calculix.fem_chain import FEMChain2324chain = FEMChain()25result = chain.run_plate_validation(sigma_applied=100.0)26print(f"Kt = {result['kt']:.3f}") # ~3.0 within 5%27```2829## Custom Analysis3031```python32from pathlib import Path33from digitalmodel.solvers.calculix.fem_chain import FEMChain3435chain = FEMChain(work_dir=Path("/tmp/my_fem"))3637# 1. Create geometry (quarter-symmetry plate with hole)38stats = chain.create_plate_with_hole(39 plate_w=200.0, plate_h=200.0, hole_r=10.0,40 thickness=1.0, element_size=5.0,41)4243# 2. Setup analysis44chain.setup_analysis(45 material={"name": "STEEL", "E": 210000.0, "nu": 0.3},46 loads=[{47 "type": "cload", "node_set": "LOAD",48 "dof": 1, "magnitude": 100.0, "direction": (1, 0, 0),49 }],50 boundary_conditions=[51 {"node_set": "SYM_X", "dof_start": 1, "dof_end": 1},52 {"node_set": "SYM_Y", "dof_start": 2, "dof_end": 2},53 {"node_set": "FIX_Z", "dof_start": 3, "dof_end": 3},54 ],55)5657# 3. Solve58status = chain.solve()59assert status["success"]6061# 4. Results62results = chain.extract_results()63print(f"Max von Mises: {results['max_von_mises']:.1f} MPa")64print(f"Max displacement: {results['max_displacement']:.6f} mm")65```6667## Key Classes6869| Class | Module | Purpose |70|-------|--------|---------|71| `FEMChain` | `solvers.calculix.fem_chain` | End-to-end orchestrator |72| `INPWriter` | `solvers.calculix.inp_writer` | Mesh → INP file conversion |73| `CalculiXResultParser` | `solvers.calculix.result_parser` | `.frd`/`.dat` parsing |74| `GMSHMeshGenerator` | `solvers.gmsh_meshing.mesh_generator` | STEP import + meshing |7576## Prerequisites7778- `gmsh` Python package (pip install gmsh)79- `ccx` binary on PATH (CalculiX solver)80- Check availability: `from digitalmodel.solvers.calculix.fem_chain import is_calculix_available`8182## Node Sets (Plate-with-Hole)8384| Set | Description |85|-----|-------------|86| `SYM_X` | Nodes on x=0 symmetry plane |87| `SYM_Y` | Nodes on y=0 symmetry plane |88| `FIX_Z` | Nodes on z=0 face (out-of-plane constraint) |89| `LOAD` | Nodes on far edge (x=W/2) for applied traction |9091## Validated Results9293- Plate-with-hole Kt within 5% of theoretical 3.0 (d/W < 0.3)94- Quarter-symmetry model with W/d > 5