Structural analysis in Python
Build a beam or a frame in a few lines, solve it with a Rust finite-element engine, and get reactions, internal forces, deflections and a Eurocode member check back as ordinary data you can loop over, assert on and put in a report. Run the solver locally with pip install FERS, or call the hosted REST API from any language — the same engine that runs in your browser on the free calculators.
Two ways to run it
Locally
pip install FERS gives you the model-building layer and pulls in the compiled solver as a binary wheel. Nothing leaves your machine, there is no request round-trip, and it works offline and inside a locked-down network. The right choice for batch work, notebooks and CI.
Hosted
POST /api/sdk/solve takes a model as JSON and returns the solved results. No install and no wheel to vendor, so it works from Node, Go, a shell script or a spreadsheet as well as from Python — and it is the same endpoint the MCP server calls underneath.
Quick start
1. Install
pip install FERSThe package needs Python 3.11 or newer. It installs the model-building layer plus the compiled solver.
2. Build a beam, solve it, and check it by hand
from fers_core import (
FERS, Node, Member, Section, Material, MemberSet, NodalSupport, NodalLoad,
)
model = FERS()
node1 = Node(0, 0, 0) # fixed end
node2 = Node(5, 0, 0) # free end, 5 m span
steel = Material(name="Steel S235", e_mod=210e9, g_mod=80.769e9,
density=7850, yield_stress=235e6)
# i_z is the strong axis, i_y the weak one — the convention that catches
# everyone exactly once.
section = Section(name="IPE 180", material=steel,
i_y=1.009e-6, i_z=13.17e-6, j=0.0477e-6, area=0.00240)
beam = Member(start_node=node1, end_node=node2, section=section)
node1.nodal_support = NodalSupport() # fully fixed
model.add_member_set(MemberSet(members=[beam]))
load_case = model.create_load_case(name="End Load")
NodalLoad(node=node2, load_case=load_case, magnitude=-1000, direction=(0, 1, 0))
model.run_analysis()
dy = model.resultsbundle.loadcases["End Load"].displacement_nodes["2"].dy
print(f"Tip deflection: {dy * 1000:.3f} mm")
# Tip deflection: -15.065 mm
# Hand check: PL^3 / 3EI_z = 1000 * 5**3 / (3 * 210e9 * 13.17e-6) = 15.0655 mmThat is the whole point of the exercise: a number you can verify with a formula you already know, before you trust the solver with a model you cannot check by hand. The same closed-form comparisons are published on the accuracy page, and the standard NAFEMS benchmarks are re-solved live in the browser.
Eurocode 3 checks from a script
A plain model gives you forces. check_beam goes one step further: it adds a ULS combination and an EN 1993-1-1 member check over the span, so one call returns bending, shear, combined N+M and lateral-torsional buckling utilizations with the per-clause trace behind each.
from fers_core import check_beam
# 7.5 m simply supported IPE400 in S275, 12 kN/m characteristic, ULS factor 1.35
beam = check_beam(7.5, "IPE400", material="S275", udl=12_000, uls_factor=1.35)
beam.run_analysis()
for row in beam.unity_check_results():
print(row["governing"]["demand"])
# 0.8002749049232664Buckling lengths default to the full span for a single-member model, so if the compression flange is restrained along its length — by decking, by a slab, by purlins — that is a modelling decision you make explicitly rather than one the default quietly makes for you. The worked EC3 example shows the same check with every clause written out.
The thing a web form cannot do
Five sections, five solves, one loop:
import os
import requests
KEY = os.environ["FERS_API_KEY"]
for section in ["IPE300", "IPE330", "IPE360", "IPE400", "IPE450"]:
response = requests.post(
"https://ferscloud.com/api/sdk/check-beam",
headers={"X-API-Key": KEY},
json={
"span_m": 7.5,
"section": section,
"material": "steel_S275",
"support": "simply_supported",
"udl": 12.0, # kN/m, characteristic
"idempotency_key": f"sweep-{section}-7m5",
},
timeout=60,
)
response.raise_for_status()
check = response.json()["check"]
print(f"{section:<8} UC {check['governing_utilization']:.3f}"
f" governed by {check['governing_check']}")That is the argument for scripting a structural calculation. The marginal cost of the sixth variant is one more entry in a list, not another twenty clicks — and the same loop works over spans, load cases, steel grades, or a CSV of members exported from your model. What it reports is which limit state governs and by how much; which section you then choose is your call, not the script's.
Pass a stable idempotency_key and reuse it on retries: a repeat with the same key replays the stored result instead of charging a second solve.
Call it from any language
curl -s https://ferscloud.com/api/sdk/solve \
-H "X-API-Key: keyId.secret" \
-H "Content-Type: application/json" \
-d '{ "model": { /* FERS model JSON */ }, "idempotency_key": "run-123" }'Endpoints: solve, validate, check-beam, create-beam, sections, schema, models and me, all under /api/sdk/. The full machine-readable spec is at ferscloud.com/api/openapi.json.
Two habits save a lot of grief. Call validate before solve — it is free and it catches broken references and misspelled keys that the solver would otherwise silently resolve to a default. And ask schema for the contract rather than guessing field names, for the same reason.
Use it from an AI agent
The same solver is exposed as a remote MCP server, so Claude, ChatGPT, Cursor and VS Code can call it directly:
{
"mcpServers": {
"fers": {
"url": "https://ferscloud.com/api/mcp",
"headers": { "X-API-Key": "keyId.secret" }
}
}
}The clients, the one-click installers, the OAuth flow and the full tool list are on the MCP server page.
Prefer JavaScript? The same engine is published on npm as a WebAssembly build that solves in the browser with no server round-trip — see structural analysis in JavaScript.
Units, axes and sign conventions
Metres, newtons and newtons per metre in the Python layer; elastic modulus in pascals; deflections come back in metres, so multiply by 1000 for millimetres. The REST beam helpers take kN and kN/m, which is why the sweep above passes 12.0 where the local call takes 12_000.
The axis convention catches everyone once: i_z is the strong (major) axis and i_y the weak one. The full set of axis, sign and unit conventions is written out on the modeling conventions page, and it is the first thing to read if a result comes back an order of magnitude off.
What it costs
The Python package is free to install and the solver runs locally, with a 100-member ceiling on the free tier. Hosted solves — REST and MCP — are free for the first 100 successful solves per rolling week, then charged from a prepaid balance, or unlimited on Pro at €19.95 a month. Only successful solves are charged. See pricing.
Frequently asked questions
Can I do structural analysis in Python?
Yes. `pip install FERS` gives you a model-building layer plus a compiled finite-element solver. You build nodes, members, sections, supports and loads as Python objects, call run_analysis(), and read displacements, internal forces and reactions off the results bundle. For the standard cases the results match the closed-form solution to within solver tolerance.
Is there a REST API for structural analysis?
Yes, at https://ferscloud.com/api/sdk/. It takes a model as JSON and returns solved results, authenticated with an X-API-Key header. The machine-readable OpenAPI spec is at /api/openapi.json, so most HTTP clients can generate bindings from it.
Do I need an API key to use the Python package?
No. The local package solves on your machine with no account and no network call. A key is only needed for the hosted REST API, for the MCP server, and for saving models to your account.
Can I run a Eurocode 3 steel check from Python?
Yes. check_beam adds an EN 1993-1-1 member check to a single-span model and returns bending, shear, combined N+M and lateral-torsional buckling utilizations, together with the per-clause trace behind each one. The same check is one call at /api/sdk/check-beam.
Does it work offline?
The local Python package does — the solver ships as a compiled wheel, not a service call, so it works with no network and inside a locked-down corporate environment. The REST API and the MCP server naturally do not.
What size of model can I solve?
The free tier caps a model at 100 members; Pro raises that to 10 000.
How many hosted solves are free?
The first 100 successful solves each rolling week are free. Only successful solves are counted, and replaying a request with the same idempotency_key returns the stored result rather than charging again.
How accurate is it?
For the cases with a closed-form solution it matches to within solver tolerance — the cantilever example on this page agrees with PL³/3EI to four significant figures. The accuracy page lists the comparisons, and the applicable NAFEMS benchmarks are re-solved live in the browser on the validation page rather than quoted from a table.
Start with the free tier
The package installs without an account. Create a free account when you want hosted solves, the MCP server, or to save models.
Prefer not to write code? Try the free 2D frame calculator or the Eurocode 3 steel beam check in your browser.