fea
Checks whether a part or an assembly of bonded parts holds under its loads, as a linear static stress study of a STEP, an xbf or a text-to-cad model, meshed by netgen and solved by CalculiX, giving peak von Mises stress, safety factor against yield and deflection drawn on the part. Use when the person asks whether a part will hold, break or is strong enough, how much it bends or sags, where it is most stressed, how much load it takes, how to make it stronger or lighter without failing, or for FEA, a stress analysis or a strength simulation. Static loads and steady g-loads only.
Try your first task
A source-grounded starter task has not been verified for this skill yet.
SKILL.md
name: feadescription: Checks whether a part or an assembly of bonded parts holds under its loads, as a linear static stress study of a STEP, an xbf or a text-to-cad model, meshed by netgen and solved by CalculiX, giving peak von Mises stress, safety factor against yield and deflection drawn on the part. Use when the person asks whether a part will hold, break or is strong enough, how much it bends or sags, where it is most stressed, how much load it takes, how to make it stronger or lighter without failing, or for FEA, a stress analysis or a strength simulation. Static loads and steady g-loads only.license: MITmetadata: repository: earthtojake/text-to-cadFEA: will it hold, and how far does it move
A study holds some faces of a part, loads others, and has CalculiX solve the linear elastic response on a netgen mesh of quadratic tetrahedra: stress and displacement under forces, pressures, the part's own weight and a steady acceleration, with an isotropic material below yield, perfectly rigid fixtures and loads that do not move. An assembly's parts are bonded where they touch. It is a first-pass engineering check, not a certification; say so when you report. Vibration, buckling, heat, flow, fatigue, impact and parts that slide on each other are not in this version: say so plainly, and do not pass a static safety factor off as an answer to them. A drop or a braking load can be estimated as a steady g-load (Body loads).
Start with the task
| Task | Start with | Reference |
|---|---|---|
| Check a part under a load | cad step solve part.step lists its faces; write the study; solve into a folder. | Workflow, Linear static |
| Check an assembly | cad step solve assembly.step lists the parts and the pairs that touch. | Assemblies |
| Write or edit a study | One JSON object: fixtures and loads, then material, mesh, margin and checks; parts and connections for an assembly. | Study file |
| Choose a material | The model's own (solve the model or its .xbf), or the E, ν and yield the user gives. | Materials |
| Judge the answer | result.json and its findings, against a hand estimate. | Findings, Judging the answer |
| Answer a question the summary does not | result.vtu, read with meshio. | Your own questions |
| Compare variants of a design | The same study on each, faces mapped, mesh size held. | Compare variants |
This skill studies a part; it does not model one. It reads a saved .step or .xbf, or a model the
engine holds by its document id (cad model solve <id>), and solves the whole document: to study one
part of an assembly alone, export it as a document of its own.
Setup
Run the cad command (~/.local/bin/cad where it is not on your PATH; cad.exe on Windows). If
it is missing, install text-to-cad, outside a sandbox or with its permission:
curl -fsSL https://texttocad.dev/install.sh | sh
On Windows, in PowerShell: irm https://www.texttocad.dev/install.ps1 | iex. If the CAD app was
only just added, its server may still be starting: try again for up to a minute first. cad doctor --check explains any other failure, changing nothing; cad doctor repairs what it reports.
The study is the solve operation of the document's type: cad step solve, cad xbf solve,
cad model solve. With no --study it lists the study's setup and writes nothing; with --study
and --out DIR it solves and writes its results into DIR. Its two tools are integrations the
cad command installs the first time a study needs them, nothing for you to install; cad run
gives a script that calls cad.step.solve both, with the kernel that reads the part.
- netgen, the mesher: the
netgenintegration (cad[netgen], about 11 MB). netgen publishes it for macOS, Linux x86_64 and Windows x86_64 alone; elsewhere (Linux on ARM among them) a solve refuses, naming the platform. - CalculiX (
ccx), the solver: thecalculixintegration (cad[calculix]: the cad-ccx package, CalculiX 2.23 for each platform, about 13 MB). A person's own CalculiX is never run unlessCAD_CCXnames the file (2.20 or newer). It runs headless, on one thread, in a private folder, so the same study gives the same numbers every run, and every result names the version that solved it.cad run ccx ARGSruns that sameccxon a deck of your own.
Units are fixed: mm, N, MPa (pressure, modulus and stress), t/mm³ for density (steel 7.85e-9) and g (9.81 m/s²) for gravity and acceleration. Restate every load in them before you write it down.
Workflow
-
List the faces. A study names faces by the engine's refs, the ones the CAD Viewer copies; a face the user picked there arrives as
/work/bracket.step#bracket/face 17and needs no lookup.cad step solve part.stepWith no study this is the setup, and writes nothing: the parts, the pairs that touch, then each face of the part, one a line: ref, area, centre, surface type and a hint such as
plane, normal -Z, largest. Match the user's words ("the mounting face") to a ref by the hint and the centre; a hole is acylinder. A document of several parts lists no faces until one is named:cad step solve assembly.step --occurrence post. A face number is a position in the saved document, so a part edited and written again is listed again before its study is re-run. -
Write the study (study-file.md):
{ "fixtures": [{"faces": ["bracket/face 17"], "type": "fixed"}], "loads": [{"faces": ["bracket/face 22"], "type": "force", "vector_N": [0, -500, 0]}] }fixedholds a face still;rollerlets it slide in its plane but not off it (a frictionless support, or a symmetry cut). Aforceis the total over its faces; apressureis in MPa, positive into the surface;gravityandaccelerationtakevector_gin g and no faces, and need the material's density.marginis the safety factor the part should keep (default 2, at least 1).checksadds adisplacementcheck with the user's limit when they gave a sag or stiffness spec; left out, the stress check alone judges the part. Leavemeshout on the first run. -
Solve into a folder.
cad step solve part.step --study study.json --out /tmp/bracket-load --json--outis any folder, a temporary one included, made when missing; put it in the project when the user should keep the files. One folder per study: a solve replaces its own files there, touches nothing else, and a run that fails leaves the previous results as they were. It holds:File What it is for result.jsonthe answer, what --jsonprints. Read this first.stress.png,displacement.pngthe deformed part coloured by each field (blue low, red high), the deformation exaggerated by deformation_scale, with a colour bar giving the field, its units and its range. They show whether the load points the way you meant and which faces are held. Show the stress one to the user.result.glbthe same coloured surface, for any glTF viewer or cad viewerresult.vtuthe volume mesh with displacement(mm) andvon_mises(MPa) at its corner nodes (Your own questions)ccx.inpwith --deck: the input CalculiX solved (the finer solve's when there were two), forcad run ccx -i ccxin that folderWhere the engine cannot draw (Linux with no display) the pictures are left out and a
solver_notesays so; everything else is written.The result is a check's:
ok,findings(each withseverity,code,message,locationandhint),written, andmeasurements: the study as given, the material, the faces it named (named_faces), the summary's figures (max_von_mises_MPaandmax_von_mises_at_mm,max_von_mises_gauss_MPa,yield_MPa,safety_factor,max_displacement_mmandmax_displacement_at_mm,applied_force_N,reaction_force_N,deformation_scale,checks; an assembly'sweakest_partandparts), each fixture's reaction,mesh(size, elements, degrees of freedom,straightened,solver),timings, andrefined, the first solve's size and peak when the run solved twice. Without--jsonthe same prints as lines.- When the safety factor comes out under 3 the run meshes again finer (half the element size, less on a big model) and solves again by itself; the finer result is the one written (Mesh).
- Progress (
[fea] meshing ...) goes to stderr, never into the result;--verboseadds mesh and solve detail there. - A malformed study (an unknown key, a face not on the part, a zero load, a load on a held face, no fixture) is refused before meshing, naming the field. A part the fixtures leave free to move, or that no load reaches, is refused by the solve; so is a solve whose reactions do not balance the applied load.
- The command exits 1 (
"ok": false) when a finding is an error: the part yields or misses a check, with the results written all the same; or the study stopped before the solve (not_connected), with nothing written. Warnings leave it at 0. Read the result either way.
-
Report with units: the peak von Mises and which feature it is near, the safety factor and the yield it is against (the low end of the model material's range), the max displacement and where, the applied load against the reaction, the mesh size and whether a finer re-solve ran; then the findings, what the model assumes, and what would change the answer most. Show
stress.png, saying the deformation is exaggerated bydeformation_scale.
Your own questions
For anything the summary does not answer (the stress at the mounting holes, the sag along an
edge, how much of the part is above some stress), read result.vtu rather than solving again.
meshio or PyVista read it as it is (uv run --with meshio):
import meshio, numpy as np
mesh = meshio.read("/tmp/bracket-load/result.vtu")
xyz, stress = mesh.points, mesh.point_data["von_mises"] # mm, MPa
moved = np.linalg.norm(mesh.point_data["displacement"], axis=1) # mm
near = np.linalg.norm(xyz - [42, 12, 3], axis=1) < 5 # within 5 mm of a point
print(stress[near].max(), moved[xyz[:, 2] > 49].max())
It holds the corner nodes of the tetrahedra, inside the part as well as on its skin; the reported
peak also counts the mid-edge nodes, so it can be a little higher than the VTU's own maximum. An
assembly's cells carry their part (part, the index into the summary's parts).
Assemblies
A document of several parts is solved as one assembly: the parts that touch are bonded into one conforming mesh, each keeps its own material, and each part's stress is judged against its own yield. Every part must reach a fixed part through bonded neighbours. The keys are in study-file.md.
The setup (cad step solve assembly.step) prints each part (ref, name, volume), then each pair:
bonded, with its contact area and gap; not connected for a near miss (a gap up to 1 mm, beyond
contact_tolerance_mm); overlapping · N mm³ where the solids share volume, which is never
bonded. An overlap no deeper than the tolerance is an interference (a press fit, or a modelling
slip): it is listed bonded with interference N mm and closed like a gap. Read the listing
against the design: is each detected joint a real one, and is a joint you expect missing? It
judges by the 0.1 mm default; a study that should bond a wider gap sets contact_tolerance_mm
from the gap printed. Names can repeat (two parts called bar): use the ref (frame/bar.2) when
one does.
Each part is solved with its model's own material; parts gives a part the numbers the user
gives, and a part with no material in its model and none in the study is refused, naming it
(Materials). connections only overrides a detection (free for a
pair that must not be glued); touching pairs are bonded without it, and a pair set free inside a
group glued through other parts is refused. Fixtures and loads name faces on any part
(post/face 23), but not a face wholly covered by a bonded joint (refused, naming the face); a
face another part only partly covers is held or loaded on its uncovered area. Connections are
bonded or free: parts that press and slide on each other, and bolts, are not in this version.
The finer re-solve runs when the weakest part's safety factor is under 3. The summary's
yield_MPa and safety_factor are the weakest part's (weakest_part, weakest_part_peak_MPa),
while max_von_mises_MPa and max_displacement_mm span the whole assembly: the highest stress
can sit in a stronger part, so do not divide one by the other; each part's own numbers are in
parts. Each finding names its part ("'post' yields: ..."): fix that part (a thicker section, a
fillet, its material in parts, a larger joint, whose area_mm2 is in the result's
connections), not the assembly in general.
Compare variants
Each version of a design is its own document; run the same study on each into its own folder and
compare the result.jsons. Face numbers are not stable between versions: an edit renumbers them,
and a ref reused unchecked lands on a different face with no error, so list each variant's faces
and map the baseline's by surface type, normal, centre and area, asking when two fit. Give every
study the baseline's mesh.size_mm, so a difference is the design's and not the mesh's, and give
the mapping (baseline bracket/face 17 → bracket/face 21, the mounting face) with the table so the
user can check it.
Findings
Two von Mises peaks are reported. The nodal peak (max_von_mises_MPa, the one the safety factor
uses) is each element's stress at its integration points, extrapolated to its nodes and averaged
over the elements at a node, per part in an assembly; it is usually the higher of the two. The
integration-point peak (max_von_mises_gauss_MPa) is the raw element value; more than 50 %
above the nodal one, it means a concentration the mesh has not resolved. Safety factor = yield /
nodal peak of the solve that is written. The edge of a perfectly rigid fixture or bonded joint and
a sharp inside corner are singularities: the peak there grows with every refinement and never
converges, so the findings below say when to read the stress a little away from it instead.
Findings list errors first: an error makes the part unfit to use, a warning is a judgment to weigh
and act on or explain. Most carry the face (bracket/face 12, the original part's ref) when the
point is on one, and the point in mm. peak_at_fixture and peak_concentration appear only when
the safety factor is under the study's margin and a finer solve did not settle the peak (moved
it under 10 %); above the margin they would not change the answer.
| Finding | Severity | What it means | What to do |
|---|---|---|---|
yields | error | The nodal peak is above the material's yield. | Strengthen the part where the peak is, change the material, or confirm the load; a peak_at_fixture or peak_concentration beside it comes first: the peak may be the model's, not the part's. |
low_margin | warning | It holds, but under the study's margin. | As for yields, or report the margin it has; never lower margin to clear the finding. |
displacement_over_limit | error | A displacement check's largest displacement (over its faces, else the whole model) is past its limit_mm. | Stiffen the part, or confirm the limit with the user. |
peak_at_fixture | warning | The peak sits on a fixed face or its edge, where a rigid clamp exaggerates stress, and a finer solve did not settle it. | Read the stress a little away from the face (the colours, or a probe in the VTU) before redesigning; if that is still high, the finding beside it stands. |
peak_concentration | warning | The integration-point peak is well above the nodal one: a sharp corner or a concentrated load the mesh cannot resolve. | Under a safety factor of 3 the run already solved finer, so refining the whole part again is not the next step: fillet the corner or spread the load over a larger face. Above 3 (a high margin), refine once and compare (Mesh). |
mesh_not_converged | warning | The automatic finer solve moved the peak by more than 10 %. In an assembly, only for a part whose safety factor is under 3. | A peak that kept rising sits on a singularity: fillet it or judge the stress away from it. Otherwise set a smaller mesh.size_mm before trusting the safety factor. |
large_displacement | warning | It moves more than 1 % of its size: the small-displacement model is stretched. | Check the fit against mating parts, and stiffen the part if the deflection is not acceptable. |
not_connected | error | A part, or a group of parts, has no bonded chain to a fixed part; the solve did not run. The message names the nearest part and its distance. | Make the parts touch, fix a face on the group, or raise contact_tolerance_mm when the gap is one you would call touching. |
overlapping_parts | warning | Two parts' solids overlap by more than the tolerance; they are not bonded. | Fix the geometry, or mark the pair free in connections when the overlap is an accepted shortcut (that silences it). A part held only through an overlap is not_connected. |
gap_closed | warning | Two parts a little apart, or a little into each other, within the tolerance were bonded by moving geometry that far. | Check the gap is a modelling clearance and not a real one, or the interference a slip and not a press fit whose preload matters; the stress at that joint is the model's closing, not the part's. |
bonded_edge_peak | warning | The peak sits on the edge of a bonded joint, where a rigid bond exaggerates stress; two meshes agreeing proves nothing there. | Read the stress a little away from the joint; a bolted or welded joint is softer than this model. |
solver_note | warning | About the run itself: a slow solve past 150 000 degrees of freedom, a finer solve skipped or failed, pictures not drawn. | Mention it when it bears on the answer. |