Exemples traités

Quatre scripts à coller et exécuter. Chacun indique la sortie attendue pour ses entrées exactes et la solution analytique qui a servi de contrôle : vous pouvez donc confirmer que votre installation les reproduit avant de faire confiance à un modèle personnel.

1. Console avec charge en extrémité

Une console IPE 180 de 5 m, parfaitement encastrée à une extrémité, avec une charge ponctuelle descendante de 1 kN en tête. C’est le modèle le plus simple qui parcourt toute la chaîne : géométrie, matériau, section, appui, cas de charge et calcul.

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 ✓

Contrôle manuel : δ = PL³ / 3EI_z = 1000·5³ / (3 · 210×10⁹ · 13,17×10⁻⁶) = 15,07 mm. Le solveur renvoie 15,065 mm.

2. Poutre sur deux appuis, charge centrée

Un IPE 300 de 10 m découpé en deux barres de 5 m pour disposer d’un nœud à mi-travée où charger et lire. Articulation à une extrémité, appui glissant à l’autre.

Notez les conditions d’appui explicites. L’articulation bloque les trois translations et la rotation de torsion mais laisse libres les rotations de flexion : sans blocage de la torsion, la poutre présente un mode de corps rigide et la matrice de rigidité est singulière. L’appui glissant libère en outre la translation longitudinale pour que la poutre puisse s’allonger.

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 ✓

Contrôle manuel : δ = PL³ / 48EI_z = 10000·10³ / (48 · 210×10⁹ · 83,58×10⁻⁶) = 11,87 mm. Le solveur renvoie 11,870 mm.

3. Portique sous charge horizontale

Deux poteaux HEA 200 de 4 m à pieds encastrés et une traverse IPE 300 de 6 m, chargés par une force horizontale de 5 kN en tête du poteau gauche. C’est le plus petit modèle où le fonctionnement en portique — et non une barre isolée — détermine le résultat.

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 ✓

Contrôle manuel par la méthode des rotations, en négligeant la déformation axiale : 5,30 mm. Le solveur renvoie 5,310 mm. Un traitement plus complet avec diagrammes figure dans l’exemple de portique.

4. Vérification acier selon l’Eurocode 3

check_beam construit une poutre d’une travée, la calcule et exécute les vérifications EN 1993-1-1 en un seul appel. Ici : un IPE 400 sur deux appuis de 7,5 m en S355 sous une charge répartie caractéristique de 13 kN/m, pondérée par 1,35, semelle comprimée non maintenue sur toute la portée.

Le résultat comporte un détail clause par clause plutôt qu’un nombre unique : chaque taux de travail se lit comme un calcul manuel, toutes les valeurs intermédiaires qui l’ont produit sont présentes.

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

Cela reproduit l’exemple traité Eurocode 3, où le même cas est développé clause par clause. Le déversement est déterminant avec un taux de travail de 0,82.

Contrôler avant de faire confiance

Chaque exemple ci-dessus affiche un nombre à côté de la solution analytique qu’il doit reproduire. C’est délibéré, et c’est l’habitude à reprendre : calculez un cas dont vous connaissez déjà la réponse avant de passer à un cas dont vous ne la connaissez pas.

Les tests de précision font cela sur un ensemble plus large de solutions analytiques, et la page NAFEMS exécute en direct dans votre navigateur les tests standard d’éléments finis, avec l’écart entre la valeur cible et FERS pour chacun.

Pages associées

Voir aussi

Questions fréquentes

Pourquoi l’exemple sur deux appuis a-t-il besoin de deux barres ?

Uniquement pour disposer d’un nœud à mi-travée où appliquer la charge et lire le déplacement. La formulation de l’élément est exacte pour une barre prismatique : découper la travée ne change donc pas le résultat, cela donne simplement un point d’application.

Pourquoi l’articulation bloque-t-elle la rotation de torsion ?

Libérer les trois rotations aux deux extrémités d’une poutre droite la laisse libre de tourner autour de son propre axe. Ce mode de corps rigide rend la matrice de rigidité singulière et le calcul échoue. Bloquer RX sur un appui supprime ce mode sans gêner aucune flexion.

Mes valeurs diffèrent au dernier chiffre, est-ce anormal ?

Non. Les valeurs affichées sont arrondies au millième de millimètre ; la comparaison avec la solution analytique est donnée à la précision que la formule justifie. Un écart plus important signale en général i_y et i_z intervertis ou une erreur d’unités.

D’où viennent les caractéristiques de section ?

De la bibliothèque de profilés acier FERS, livrée avec le paquet. Vous pouvez aussi passer les caractéristiques directement, comme le font ces exemples, ou les calculer pour une forme quelconque avec le calculateur de caractéristiques de section.

Puis-je exécuter ces exemples sans compte ?

Oui. Les quatre se calculent localement sans identifiant. Seuls l’enregistrement dans le cloud et les canaux API/agents comptabilisés nécessitent une clé.

Comment faire la même chose depuis JavaScript ?

Le même moteur est publié comme paquet npm en WebAssembly avec un format de modèle identique — voir utiliser FERS depuis JavaScript.