Ein Modell in Python aufbauen und rechnen
Sieben Objekte decken fast jedes Modell ab: Node, Material, Section, Member, MemberSet, NodalSupport und NodalLoad. Sie setzen sie zusammen, rufen run_analysis() auf und lesen ein nach Lastfall geordnetes Ergebnispaket aus.
Die Kernobjekte
Alles wird aus fers_core importiert. Ein Modell ist eine FERS-Instanz, die Stabgruppen hält; Lasten hängen an Lastfällen und nicht direkt am Modell, dieselbe Geometrie kann also mehrere unabhängige Lastfälle tragen.
- Node — ein X-, Y-, Z-Punkt. Y zeigt nach oben. Knoten tragen ihre Auflagerbedingung.
- Material — E-Modul, Schubmodul, Dichte, Streckgrenze. Durchgängig SI: Pascal und kg/m³.
- Section — Fläche und Flächenmomente zweiten Grades, mit Bezug auf ein Material.
- Member — ein Balkenelement mit zwei Knoten und sechs Freiheitsgraden je Knoten, mit Bezug auf einen Querschnitt.
- MemberSet — die Gruppe, die Sie dem Modell hinzufügen, und zugleich die Einheit, auf die Nachweise angewendet werden.
- NodalSupport — die einem Knoten zugewiesene Randbedingung.
- NodalLoad — eine Kraft oder ein Moment, das innerhalb eines Lastfalls auf einen Knoten wirkt.
from fers_core import (
FERS, Node, Member, Section, Material,
MemberSet, NodalSupport, NodalLoad
)Geometrie, Material und Querschnitt definieren
Koordinaten in Metern, Materialkennwerte in Pascal. Der folgende Querschnitt ist ein IPE 180 aus der FERS-Profilbibliothek.
Beachten Sie die Achsenkonvention, denn sie ist mit Abstand die häufigste Ursache für ein falsches Ergebnis: i_z ist die starke Achse, i_y die schwache. Ein Träger, der sich in seiner üblichen Ebene biegt, wird von i_z bestimmt.
# Nodes (x, y, z coordinates in metres)
node1 = Node(0, 0, 0)
node2 = Node(5, 0, 0)
# Material (Steel S235)
steel = Material(
name="Steel S235",
e_mod=210e9, # Pa
g_mod=80.769e9, # Pa
density=7850, # kg/m³
yield_stress=235e6 # Pa
)
# Cross-section (IPE 180), values from the FERS steel section library.
# Axis convention: i_z is the STRONG axis (bending in the local x-y plane),
# i_y the weak axis — see ferscloud.com/conventions
section = Section(
name="IPE 180",
material=steel,
i_y=1.009e-6, # m⁴ (weak axis)
i_z=13.17e-6, # m⁴ (strong axis)
j=0.0477e-6, # m⁴
area=0.00240 # m²
)Alle Achsen-, Vorzeichen- und Einheitenkonventionen stehen auf der Konventionsseite. Der JSON-Vertrag erwartet Winkel in Grad, nicht im Bogenmaß.
Stab erzeugen, Auflager und Last aufbringen
Ein bloßes NodalSupport() ist voll eingespannt. Für ein Gelenk- oder Rollenlager übergeben Sie displacement_conditions und rotation_conditions explizit — die Beispiele zeigen beides.
Lastrichtungen sind globale Einheitsvektoren, (0, 1, 0) mit negativem Betrag ist also eine nach unten gerichtete Kraft.
# Create beam element
beam = Member(start_node=node1, end_node=node2, section=section)
# Fixed support at node1
node1.nodal_support = NodalSupport()
# Organise members into a set and add to model
model = FERS()
model.add_member_set(MemberSet(members=[beam]))
# Load case with a −1 kN point load at node2
lc = model.create_load_case(name="Gravity")
NodalLoad(node=node2, load_case=lc, magnitude=-1000, direction=(0, 1, 0))Berechnung starten und Ergebnisse lesen
run_analysis() rechnet jeden Lastfall. Die Ergebnisse liegen unter model.resultsbundle, geordnet nach Lastfallnamen, mit Verformungen und Auflagerkräften nach Knoten-ID als Zeichenkette.
Die Kommentare zeigen die tatsächliche Ausgabe für genau diese Eingaben.
model.run_analysis()
results = model.resultsbundle.loadcases["Gravity"]
dy = results.displacement_nodes["2"].dy
Vy = results.reaction_nodes["1"].nodal_forces.fy
Mz = results.reaction_nodes["1"].nodal_forces.mz
print(f"Tip deflection : {dy*1000:.3f} mm") # -15.065 mm
print(f"Reaction Vy : {Vy:.1f} N") # 1000.0 N
print(f"Reaction Mz : {Mz:.1f} Nm") # 5000.0 NmHandrechnung: Ein 5 m langer Kragarm mit Biegung um die starke Achse liefert δ = PL³ / 3EI_z = 1000·5³ / (3 · 210×10⁹ · 13,17×10⁻⁶) = 15,07 mm, dazu aus dem Gleichgewicht eine Auflagerkraft von 1 kN und ein Einspannmoment von 5 kN·m. Der Solver gibt 15,065 mm zurück.
Ergebnisse lesen, speichern und wieder laden
Seit FERS 0.1.98 sind member_results und displacement_nodes schreibgeschützte Tabellen. Sie lesen sich wie Dictionaries — [], get, in, .items() —, aber jeder Zugriff erzeugt ein neues Objekt, das sich nicht ändern lässt. Genau das hält ein großes Ergebnis im Speicher klein. .copy() liefert ein gewöhnliches Dictionary mit änderbaren Objekten.
save_to_json schreibt das Modell samt Ergebnissen, und FERS.from_json liest jede Datei zurück, die das SDK oder der Solver geschrieben hat, Eintrag für Eintrag. Bei einem großen Modell schreibt am besten der Solver die Datei selbst, mit run_analysis_to_file: Dann läuft das Ergebnis nie als eine einzige Zeichenkette durch Python.
from fers_core import FERS
results = model.resultsbundle.loadcases["Gravity"]
# A read-only table: every lookup builds a fresh object
beam_result = results.member_results["1"]
print(beam_result.local_start_forces.mz)
editable = results.member_results.copy() # a plain dict of editable objects
editable["1"].local_start_forces.mz = 0.0
model.save_to_json("cantilever.json") # the model and its results
reloaded = FERS.from_json("cantilever.json")
# A large model: let the solver write the file itself
model.run_analysis_to_file("cantilever_results.json")
solved = FERS.from_json("cantilever_results.json")Nur die Ergebnisse anfordern, die Sie lesen
result_filter behält oder verwirft ganze Ergebnisblöcke. result_requests (FERS 0.1.99) schränkt einen Block auf die Stäbe oder Knoten, Lastkombinationen, Komponenten und das Stabende ein, die ein Nachweis tatsächlich liest. Die Werte landen in den gewohnten member_results, displacement_nodes und reaction_nodes; alles nicht Angeforderte liest sich als None, sodass ein Nachweis nie mit einer Null besteht, die niemand berechnet hat.
Lastkombinationen werden über ihren limit_state ausgewählt, so wie Bemessungsnachweise sie auswählen; setzen Sie ihn also an jeder Kombination. Die Werte selbst stehen in resultsbundle.selections: ein Array je Anforderung mit der Form (Ergebnissätze, IDs, Felder, Komponenten), jede Achse daneben aufgelistet.
from fers_core import ResultBlock, ResultRequest
from fers_core.loads.enums import LimitState
from fers_core.result_requests import nodes_of
from fers_core.unity_checks import members
# Requests select load combinations by limit state, as design checks do
uls = model.create_load_combination("ULS 1", {lc: 1.35}, situation="ULS", check="ALL")
uls.limit_state = LimitState.ULS
beams = members([beam.id])
model.settings.analysis_options.result_requests = [
ResultRequest(ResultBlock.LOCAL_END_FORCES, members=beams,
limit_state="ULS", end="start", components=["fy", "mz"]),
ResultRequest(ResultBlock.NODE_DISPLACEMENTS, nodes=nodes_of(beams),
limit_state="ULS", components=["dy"]),
]
model.run_analysis()
uls_results = model.resultsbundle.loadcombinations["ULS 1"]
start = uls_results.member_results["1"].local_start_forces
print(start.mz) # requested
print(start.my) # None: not requested
selection = model.resultsbundle.selections[0]
print(selection["fields"], selection["components"])
print(selection["values"].shape) # (result sets, ids, fields, components)Bei einem Regalmodell mit 4 Feldern, 8.546 Stäben und 31 Lastkombinationen schrumpfte die Ergebnisdatei von 452 MB auf 41 MB, mit nur den Werten, die seine Nachweise lesen.
Einen durchlaufenden Träger auf dem drehen lassen, was er kreuzt
Eine Schiene, die über Träger läuft, ist über ihre Länge durchlaufend, auf jedem Träger aber frei drehbar. Ein MemberHinge gibt ein Stabende frei; beide Schienenenden an einem Träger freizugeben, würde die Schiene in zwei Felder teilen. Geben Sie den Stäben der Schiene einen eigenen Stabsatz mit einem ScissorHinge (FERS 0.1.99): Der Satz bleibt in sich verbunden und dreht oder gleitet auf jedem Stab außerhalb des Satzes, auf den er trifft – ohne Koppelstab oder zusätzlichen Knoten.
Jeder Wert wirkt wie eine Freigabe eines Stabgelenks: None hält die Achse, 0.0 gibt sie frei, und ein positiver Wert ist eine Feder. Die Achsen sind global, sofern das Gelenk nicht mit ReleaseAxes.user(x, y) ein Achsensystem nennt; scissor_hinge_nodes beschränkt das Gelenk auf einige Knoten des Satzes, und ein MemberHinge kann seine Verdrehungen mit rotation_axes um globale oder eigene Achsen nehmen. Ein Modell, das eines davon verwendet, wird mit schema_version 3 geschrieben, sodass ein älterer Solver es ablehnt, statt jeden Anschluss starr zu rechnen.
from fers_core import FERS, DistributedLoad, Material, Member, MemberSet, NodalSupport, Node, ScissorHinge, Section
from fers_core.supports.supportcondition import SupportCondition as C
model = FERS()
steel = Material(name="S355", e_mod=210e9, g_mod=81e9, density=7850.0, yield_stress=355e6)
rail_section = Section(name="rail", material=steel, i_y=1e-6, i_z=1e-6, j=1e-7, area=1e-3)
beam_section = Section(name="beam", material=steel, i_y=1e-4, i_z=1e-4, j=1e-4, area=5e-3)
turns = {"X": C.fixed(), "Y": C.free(), "Z": C.free()}
a, m, b = Node(0.0, 0.0, 0.0), Node(1.0, 0.0, 0.0), Node(2.0, 0.0, 0.0)
a.nodal_support = NodalSupport(rotation_conditions=turns)
b.nodal_support = NodalSupport(
displacement_conditions={"X": C.free(), "Y": C.fixed(), "Z": C.fixed()}, rotation_conditions=turns
)
beam_start, beam_end = Node(1.0, 0.0, -0.5), Node(1.0, 0.0, 0.5)
beam_start.nodal_support = beam_end.nodal_support = NodalSupport() # clamped
rail_1 = Member(start_node=a, end_node=m, section=rail_section)
rail_2 = Member(start_node=m, end_node=b, section=rail_section)
model.add_member_set(MemberSet(
members=[rail_1, rail_2],
scissor_hinge=ScissorHinge(rotational_release_y=0.0, rotational_release_z=0.0),
))
model.add_member_set(MemberSet(members=[
Member(start_node=beam_start, end_node=m, section=beam_section),
Member(start_node=m, end_node=beam_end, section=beam_section),
]))
span = model.create_load_case(name="span")
DistributedLoad(member=rail_1, load_case=span, magnitude=1000.0, end_magnitude=1000.0, direction=(0, -1, 0))
model.run_analysis()
mz = model.resultsbundle.loadcases["span"].member_results[str(rail_1.id)].local_end_forces.mz
print(f"{abs(mz):.1f} Nm") # 62.4; a knife edge gives qL²/16 = 62.5, a rigid joint 122.6Handrechnung: Eine über zwei Felder von 1 m durchlaufende Schiene, von denen eines belastet ist, hat über der Mittelstütze das Moment qL²/16 = 1000 · 1² / 16 = 62,5 N·m. Der Solver liefert 62,4 N·m, weil der Träger unter der Schiene etwas nachgibt; starr mit dem Träger verbunden, nimmt die Schiene 122,6 N·m auf.
Über die lineare Statik hinaus
Dasselbe Modellobjekt trägt die Einstellungen der übrigen Berechnungsarten. Berechnung nach Theorie II. Ordnung (P-Delta), lineares Beulen mit kritischem Laststeigerungsfaktor, Modalanalyse und Antwortspektrum-Erdbebenberechnung werden alle über Analyseeinstellungen gesteuert, nicht über eine andere Schnittstelle.
Nachweise werden an Stabgruppen gehängt und nach der Berechnung ausgewertet. Sie liefern klauselweise Ausnutzungen samt der Zwischenwerte, aus denen sie entstanden sind — ein Nachweis liest sich also wie eine Handrechnung und nicht wie eine einzelne Zahl.
- Prüfen Sie zuerst gegen geschlossene Lösungen — siehe Genauigkeits-Benchmarks und NAFEMS.
- Für Nachweise nach EN 1993-1-1 baut, rechnet und prüft
check_beamein Einfeld in einem Aufruf — siehe die Beispiele.
Verwandte Seiten
Das FERS-Python-Paket installieren
Mit pip installieren, den Import prüfen und optional die Cloud-Authentifizierung per API-Schlüssel oder Token einrichten.
Durchgerechnete Beispiele
Vier lauffähige Skripte — Kragarm, Einfeldträger, Rahmen und ein Nachweis nach EN 1993-1-1 — jeweils mit Handrechnung.
FERS im Terminal und aus Coding-Agenten
Der Befehl fers: Modelle aus einer Shell oder einem Coding-Agenten prüfen, in eine Datei rechnen, nachweisen und inspizieren, mit einer Skill-Datei für den Arbeitsablauf.
Siehe auch
Häufige Fragen
Warum sind meine Verformungen über Zeichenketten indiziert?
displacement_nodes["2"], nicht [2].Warum löst das Ändern eines Ergebnisses einen Fehler aus?
.copy() auf member_results oder displacement_nodes auf, um ein gewöhnliches Dictionary mit änderbaren Objekten zu erhalten.Wofür ist ein MemberSet da?
Wie modelliere ich ein Gelenk- oder Rollenlager?
NodalSupport explizite Bedingungen. Ein Gelenklager hält die drei Verschiebungen und lässt die Biegeverdrehungen frei; halten Sie zusätzlich die Torsionsverdrehung, sonst hat der Stab eine Starrkörper-Drehung und die Berechnung wird singulär. Das Einfeldträger-Beispiel zeigt beides.Welches Flächenmoment ist die starke Achse?
i_z. FERS behandelt die lokale z-Achse durchgängig als starke Biegeachse — Solver, Nachweise und Ergebnislinien sind sich darin einig. Vertauschte i_y und i_z sind der häufigste Modellierfehler.Brauche ich für die Berechnung eine Internetverbindung?
run_analysis() führt den kompilierten Solver in Ihrem eigenen Prozess aus. Netzwerkzugriff entsteht nur, wenn Sie einen Cloud-Endpunkt aufrufen.