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.82

Esto 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

Véase también

Preguntas frecuentes

¿Por qué el ejemplo de viga biapoyada necesita dos barras?

Solo para tener un nudo en el centro del vano donde aplicar la carga y leer el desplazamiento. La formulación del elemento es exacta para una barra prismática, así que dividir el vano no cambia el resultado: únicamente da un punto de aplicación.

¿Por qué la articulación retiene el giro de torsión?

Liberar los tres giros en ambos extremos de una viga recta la deja libre para girar sobre su propio eje. Ese modo de sólido rígido hace singular la matriz de rigidez y el cálculo falla. Retener RX en un apoyo elimina el modo sin coartar ninguna flexión.

Mis números difieren en el último dígito, ¿algo va mal?

No. Los valores impresos están redondeados a tres decimales de milímetro; la comparación con la solución cerrada se da con la precisión que la fórmula justifica. Una diferencia mayor suele significar i_y e i_z intercambiados o un error de unidades.

¿De dónde salen las propiedades de las secciones?

De la biblioteca de perfiles de acero de FERS, que se distribuye con el paquete. También puede pasar las propiedades directamente, como hacen estos ejemplos, o calcularlas para una forma cualquiera con la calculadora de propiedades de sección.

¿Puedo ejecutar estos ejemplos sin cuenta?

Sí. Los cuatro se calculan localmente sin credenciales. Solo el almacenamiento en la nube y los canales API/agentes medidos requieren clave.

¿Cómo hago lo mismo desde JavaScript?

El mismo motor se publica como paquete npm en WebAssembly con un formato de modelo idéntico — véase usar FERS desde JavaScript.