Ejemplos resueltos
Cuatro scripts que puede pegar y ejecutar. Cada uno indica la salida esperada para sus entradas exactas y la solución cerrada con la que se contrastó, de modo que puede confirmar que su instalación los reproduce antes de fiarse de un modelo propio.
1. Ménsula con carga en el extremo
Una ménsula IPE 180 de 5 m, totalmente empotrada en un extremo, con una carga puntual descendente de 1 kN en la punta. Es el modelo más simple que recorre toda la cadena: geometría, material, sección, apoyo, hipótesis de carga y cálculo.
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)
# IPE 180 from the FERS section library: i_z = strong axis (in play here), i_y = weak axis
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]))
lc = model.create_load_case(name="End Load")
NodalLoad(node=node2, load_case=lc, 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")
# Expected output: Tip deflection: -15.065 mm
# Hand check: δ = PL³/3EI_z = 1000·5³ / (3 · 210e9 · 13.17e-6) = 15.07 mm ✓Comprobación manual: δ = PL³ / 3EI_z = 1000·5³ / (3 · 210×10⁹ · 13,17×10⁻⁶) = 15,07 mm. El solver devuelve 15,065 mm.
2. Viga biapoyada con carga centrada
Un IPE 300 de 10 m dividido en dos barras de 5 m para tener un nudo en el centro del vano donde cargar y leer. Articulación en un extremo y apoyo deslizante en el otro.
Fíjese en las condiciones de apoyo explícitas. La articulación retiene las tres traslaciones y el giro de torsión, pero deja libres los giros de flexión: si no retiene la torsión, la viga tiene un modo de sólido rígido y la matriz de rigidez es singular. El apoyo deslizante libera además la traslación longitudinal para que la viga pueda alargarse.
from fers_core import FERS, Node, Member, Section, Material, MemberSet, NodalSupport, NodalLoad
model = FERS()
node1 = Node(0, 0, 0)
node2 = Node(5, 0, 0) # mid-span
node3 = Node(10, 0, 0) # right support
steel = Material(name="Steel S235", e_mod=210e9, g_mod=80.769e9, density=7850, yield_stress=235e6)
section = Section(name="IPE 300", material=steel, i_y=6.038e-6, i_z=83.58e-6, j=0.199e-6, area=0.00538)
beam1 = Member(start_node=node1, end_node=node2, section=section)
beam2 = Member(start_node=node2, end_node=node3, section=section)
# Pin at node1 — bending rotations free, torsion (RX) held so the beam
# has no rigid-body twist mode. Roller at node3 — X translation free too.
pin = NodalSupport(
displacement_conditions={"X": "Fixed", "Y": "Fixed", "Z": "Fixed"},
rotation_conditions={"X": "Fixed", "Y": "Free", "Z": "Free"},
)
roller = NodalSupport(
displacement_conditions={"X": "Free", "Y": "Fixed", "Z": "Fixed"},
rotation_conditions={"X": "Free", "Y": "Free", "Z": "Free"},
)
node1.nodal_support = pin
node3.nodal_support = roller
model.add_member_set(MemberSet(members=[beam1, beam2]))
lc = model.create_load_case(name="Centre Load")
NodalLoad(node=node2, load_case=lc, magnitude=-10000, direction=(0, 1, 0))
model.run_analysis()
dy_mid = model.resultsbundle.loadcases["Centre Load"].displacement_nodes["2"].dy
print(f"Mid-span deflection: {dy_mid*1000:.3f} mm")
# Expected output: Mid-span deflection: -11.870 mm
# Hand check: δ = PL³/48EI_z = 10000·10³ / (48 · 210e9 · 83.58e-6) = 11.87 mm ✓Comprobación manual: δ = PL³ / 48EI_z = 10000·10³ / (48 · 210×10⁹ · 83,58×10⁻⁶) = 11,87 mm. El solver devuelve 11,870 mm.
3. Pórtico bajo carga horizontal
Dos pilares HEA 200 de 4 m con bases empotradas y un dintel IPE 300 de 6 m, cargados con una fuerza horizontal de 5 kN en la cabeza del pilar izquierdo. Es el modelo más pequeño en el que el comportamiento de pórtico — y no una barra aislada — determina el resultado.
from fers_core import FERS, Node, Member, Section, Material, MemberSet, NodalSupport, NodalLoad
model = FERS()
# Portal frame: two columns (h=4 m) + one beam (L=6 m)
n1 = Node(0, 0, 0) # left base
n2 = Node(0, 4, 0) # left top
n3 = Node(6, 4, 0) # right top
n4 = Node(6, 0, 0) # right base
steel = Material(name="Steel S235", e_mod=210e9, g_mod=80.769e9, density=7850, yield_stress=235e6)
col_sec = Section(name="HEA 200", material=steel, i_y=13.36e-6, i_z=36.93e-6, j=0.206e-6, area=0.00538)
beam_sec = Section(name="IPE 300", material=steel, i_y=6.038e-6, i_z=83.58e-6, j=0.199e-6, area=0.00538)
col_left = Member(start_node=n1, end_node=n2, section=col_sec)
col_right = Member(start_node=n4, end_node=n3, section=col_sec)
rafter = Member(start_node=n2, end_node=n3, section=beam_sec)
n1.nodal_support = NodalSupport() # fixed base
n4.nodal_support = NodalSupport() # fixed base
model.add_member_set(MemberSet(members=[col_left, col_right, rafter]))
lc = model.create_load_case(name="Wind")
# Horizontal wind load on left column top
NodalLoad(node=n2, load_case=lc, magnitude=5000, direction=(1, 0, 0))
model.run_analysis()
dx = model.resultsbundle.loadcases["Wind"].displacement_nodes["2"].dx
print(f"Sway at left top: {dx*1000:.3f} mm")
# Expected output: Sway at left top: 5.310 mm
# Hand check (slope-deflection, axial deformation neglected): 5.30 mm ✓Comprobación manual por el método de los giros, despreciando la deformación axil: 5,30 mm. El solver devuelve 5,310 mm. Un tratamiento más completo con diagramas está en el ejemplo de pórtico.
4. Comprobación de acero según Eurocódigo 3
check_beam construye una viga de un vano, la calcula y ejecuta las comprobaciones de EN 1993-1-1 en una sola llamada. Aquí: un IPE 400 biapoyado de 7,5 m en S355 bajo una carga uniforme característica de 13 kN/m, mayorada por 1,35 y con el ala comprimida sin arriostrar en toda la luz.
El resultado incluye una traza cláusula a cláusula en lugar de un único número, de modo que cada aprovechamiento se lee como un cálculo manual: están todos los valores intermedios que lo produjeron.
from fers_core import check_beam
# 7.5 m simply supported IPE 400 in S355, 13 kN/m characteristic UDL,
# ULS factor 1.35, compression flange unrestrained over the full span
model = check_beam(
span=7.5,
section="IPE400",
material="S355",
udl=13_000, # N/m characteristic (13 kN/m)
uls_factor=1.35,
)
model.run_analysis()
check = model.unity_check_results()[0]
print(f"Governing UC: {check['max_utilization']:.2f}")
for step in check["governing"]["trace"]:
print(f" {step['label']:22s} {step['value']:.2f}")
# Expected output (solver-computed, matches the published worked example):
# Governing UC: 0.82
# Bending y (6.2.5) 0.00
# Bending z (6.2.5) 0.27
# Shear z (6.2.6) 0.00
# Shear y (6.2.6) 0.07
# Combined N+M (6.2.1) 0.27
# LTB (6.3.2) 0.82
# Governing 0.82Esto reproduce el ejemplo resuelto de Eurocódigo 3, donde el mismo caso se desarrolla cláusula a cláusula. Gobierna el pandeo lateral por torsión con un aprovechamiento de 0,82.
Contrastar antes de confiar
Cada ejemplo de arriba imprime un número junto a la solución cerrada que debería reproducir. Es deliberado, y es el hábito que conviene copiar: calcule un caso cuya respuesta ya conoce antes de escalar a otro que no.
Los contrastes de precisión hacen esto sobre un conjunto más amplio de soluciones cerradas, y la página NAFEMS ejecuta los contrastes estándar de elementos finitos en directo en su navegador, con el error entre el valor objetivo y FERS en cada caso.
Páginas relacionadas
Construir y calcular un modelo en Python
Los objetos principales de Python, cómo encajan entre sí y cómo leer desplazamientos, esfuerzos y reacciones.
Referencia de la API REST
Todos los puntos finales del SDK con petición y respuesta: autenticación, claves, cálculo, validación, comprobación de vigas y gestión de modelos.
Véase también
Preguntas frecuentes
¿Por qué el ejemplo de viga biapoyada necesita dos barras?
¿Por qué la articulación retiene el giro de torsión?
Mis números difieren en el último dígito, ¿algo va mal?
i_y e i_z intercambiados o un error de unidades.