Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,35 @@ Toutes les modifications notables de ce projet seront documentées dans ce fichi
Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
et ce projet adhère au [Semantic Versioning](https://semver.org/lang/fr/).

## [Unreleased]
## [2.1.2]

### Fixed
- **`detect_continuous_members`** : correction du bug qui empêchait la détection de la continuité d'un arbalétrier (ou de toute barre) lorsqu'une contrefiche (ou autre barre transversale) était fixée en nœud intermédiaire (jonction T/Y). La contrainte de degré 2 au nœud a été supprimée : la colinéarité seule suffit à distinguer les barres continues des branchements. La recherche du voisin parcourt désormais toutes les barres du nœud pour trouver celle qui passe le test de continuité, et non plus uniquement la première trouvée. Les tests de `TestDetectContinuousMembers` ont été mis à jour en conséquence (2 nouveaux cas de régression : jonction T perpendiculaire et jonction T avec relâchement).
- **`Compression` / `_determine_compression_params` / `verification_EC5`** : correction du calcul des longueurs et conditions d'appui de flambement (EC5 §6.3.2). Trois bugs corrigés simultanément : (1) `Compression.__init__` utilisait un seul `type_appuis`/`coef_lef` appliqué identiquement aux axes y et z — remplacé par `type_appuis_y`/`type_appuis_z` et `coef_lef_y`/`coef_lef_z` indépendants (`coef_lef` conservé pour rétro-compatibilité) ; (2) `_determine_type_appuis` utilisait `Noeuds[0/1]` pour les nœuds d'extrémité (bug topologique) et ignorait les appuis intermédiaires — remplacé par `_determine_compression_params` qui découpe la barre en sous-portées via `_compute_spans` et détermine le `type_appuis` à chaque sous-portée via le nouveau helper `_type_appuis_between_nodes` ; (3) `verification_EC5` passait `type_appuis_z` pour les deux axes à `Compression` — désormais `lo_flamb_y`/`lo_flamb_z` (flambement, stockés séparément de `lo_rel_y`/`lo_rel_z`) et `type_appuis_y`/`type_appuis_z` sont transmis correctement par axe. Rétro-compatibilité assurée via fallback `lo_flamb_y → lo_rel_y` si la clé est absente du Design.
- **`_determine_flexion_params`** : correction du calcul des coefficients `coeflef_y` / `coeflef_z` sur les barres structurales multi-membrures. Un seul `coeflef` global était calculé pour l'ensemble de la barre et appliqué identiquement aux deux axes, sans tenir compte de la découpe en sous-portées par les appuis latéraux ni des différences de chargement par sous-portée. La méthode calcule désormais `(lo_rel, coeflef)` **par axe et par sous-portée** : pour chaque sous-portée délimitée par les appuis latéraux d'un axe, `_coeflef_for_span` détermine le coeflef local en fonction des charges verticales (distribuées, ponctuelle centrale, ponctuelle en bout) effectivement présentes sur ce segment ; la paire `(lo_rel × coeflef)` maximale — c'est-à-dire la plus défavorable — est retenue indépendamment pour Y et Z. Le helper `_compute_spans` a été introduit (refactorisation de `_compute_lo_rel`) pour exposer la liste des segments entre appuis.
- **`_compute_lo_rel` / `_determine_flexion_params`** : correction du bug de parcours topologique sur les barres structurales multi-membrures. Les deux méthodes utilisaient `Noeuds[0]`/`Noeuds[1]` directement, supposant à tort que toutes les barres FEM d'une chaîne sont orientées dans le même sens. Les nœuds d'extrémité et intermédiaires pouvaient ainsi être incorrects (ex : dernier nœud pointant vers le milieu de la chaîne plutôt que vers l'extrémité libre). Correction via le nouveau helper **`_ordered_chain_nodes(member_ids)`** qui parcourt la topologie réelle de la chaîne (en déduisant le sens de chaque barre depuis le nœud précédent), produisant une liste ordonnée `[(node_id, abscisse_mm), …]` fiable quelle que soit l'orientation des barres FEM individuelles.

### Added
- **`ourocode/eurocode/ec5/verification.py`** : nouvelle **classe `Verification_EC5(Projet)`** de vérification EC5 d'un modèle MEF complet (barres structurales continues ou non).
- Factory :meth:`Verification_EC5.from_combinaison(combinaison, model_result)` qui hérite via `_from_parent_class([model_generator, combinaison])` des attributs Projet (ingénieur, nom, code INSEE, altitude) et attache la combinaison + le résultat MEF.
- :meth:`verify(name, elu_filter="ELU_ALL", type_bat, pos_charge, coeflef_y, coeflef_z, type_appuis_compression, n_points)` **boucle sur toutes les combinaisons ELU** : pour chaque combo, `kmod` est dérivé via :meth:`Combinaison.min_type_load` et `γM` via :meth:`Combinaison.type_combi`, puis les efforts gouvernants (Nx signé, Vy, My, Mz) sont extraits via :meth:`Model_result.get_internal_force` (ciblage par `combo_name`). Pour chaque vérification (Flexion, Cisaillement, Traction **ou** Compression selon le signe de Nx), le taux maximum rencontré et la combinaison gouvernante associée sont retenus. La flexion inclut l'interaction flexo-compression/flexo-traction via `Flexion.taux_m_d(compression=…, traction=…)`. La flèche ELS (W_inst(Q), W_net,fin) est calculée indépendamment via le max tag-based.
- :meth:`synthese(**kwargs)` : agrège toutes les barres structurales en un unique DataFrame trié par taux décroissant, avec gestion des erreurs (section manuelle, classe inconnue) en DataFrame secondaire.
- Helpers privés : `_verify_combo_elu`, `_verify_fleche`, `_efforts_for_combo`, `_deflection`, `_resolve_section`, `_resolve_classe_bois`, `_design_or_default`, `_lo_mm`, `_check_state`, `_taux_to_df`.
- Exposée depuis `ourocode.eurocode.ec5` via `__init__.py`.
- **`ourocode/eurocode/core/combinaison.py`** : nouvelle méthode `Combinaison.type_combi(name_combi) -> "Fondamentales" | "Accidentelles"` utilisée par `Verification_EC5` pour résoudre dynamiquement le coefficient partiel `γM` selon l'EC5 §2.4.1 (EN 1990 §6.4.3.2/3.3). Lève `ValueError` pour une combinaison non-ELU.
- **`tests/test_EC5_Verification.py`** : 18 tests d'intégration couvrant :
- `Combinaison.type_combi` (Fondamentales, Accidentelles, ValueError hors ELU).
- Factory `Verification_EC5.from_combinaison` : instanciation, héritage des attributs Projet depuis le modèle MEF, état valide pour `verify`.
- Poutre simple 1 travée (DataFrame non vide, Flexion+Cisaillement+Flèche présents, Traction/Compression absents sans charge axiale, ordres de grandeur, combo gouvernante `ELU_STR 1.35G + 1.5Q`).
- Boucle par combinaison : `min_type_load` retourne les bonnes durées par combo, cohérence entre `ELU_ALL` et `ELU_STR` en l'absence d'accidentelles.
- Poutre continue 2 travées (auto-groupage + synthèse, tri décroissant, présence de la combo gouvernante).
- **`ourocode/eurocode/core/model_generator.py`** : nouveau concept de **barre structurale** regroupant une ou plusieurs barres FEM continues, pour préparer l'itération et la vérification Eurocode à l'échelle d'une barre physique (solive continue, panne sur plusieurs appuis, etc.).
- `detect_continuous_members(angle_tol_deg=1.0)` : détection automatique des chaînes colinéaires de barres FEM partageant matériau/section, sans rotule (`teta_y`/`teta_z`) aux extrémités communes et sans T-junction.
- `group_members(name, member_ids, role, classe_bois, cs, Hi, Hf, effet_systeme, type_element_fleche, lo_rel_y, lo_rel_z, comment)` : regroupement manuel avec configuration de design EC5.
- `auto_group_continuous_members(angle_tol_deg, role, name_prefix, only_continuous, **design_kwargs)` : détection + regroupement en une passe.
- `get_structural_member`, `get_all_structural_members`, `del_structural_member`, `iter_structural_members` : accès et itération.
- Ajout de `"structural_members"` dans `self._data`.
- **`tests/test_model_generator.py`** : 17 tests couvrant la détection (continuité, rupture par section/matériau/rotule/T-junction/angle, tolérance angulaire, orientation inversée des extrémités) et la gestion des barres structurales (regroupement, validations, itération, auto-groupage).

## [2.0.0] - 2026-04-16

Expand Down
35 changes: 35 additions & 0 deletions ourocode/eurocode/core/combinaison.py
Original file line number Diff line number Diff line change
Expand Up @@ -1804,6 +1804,41 @@ def _get_combi_factor_load(self, nom: str) -> dict:
return dict_loads


def type_combi(self, name_combi: str) -> str:
"""Retourne le type de combinaison EC0 (``"Fondamentales"`` ou ``"Accidentelles"``).

Déduit le type à partir du préfixe du nom de la combinaison tel que
généré par :class:`Combinaison` :

- ``"ELU_STR_ACC ..."`` -> ``"Accidentelles"`` (EC0 §6.4.3.3)
- ``"ELU_STR ..."`` ou tout autre ELU -> ``"Fondamentales"`` (EC0 §6.4.3.2)

Cette information sert notamment à déterminer le coefficient partiel
``γM`` pour les vérifications Eurocode (EC5 §2.4.1, EC3 §6.1…) selon
que la situation est durable/transitoire ou accidentelle.

Args:
name_combi (str): Nom de la combinaison à analyser
(ex. ``"ELU_STR 1.35G + 1.5Q"`` ou ``"ELU_STR_ACC G + Ae"``).

Returns:
str: ``"Accidentelles"`` si le nom débute par ``ELU_STR_ACC``,
sinon ``"Fondamentales"``.

Raises:
ValueError: Si ``name_combi`` ne correspond pas à une combinaison
ELU reconnue (ni ``ELU_STR`` ni ``ELU_STR_ACC``).
"""
if name_combi.startswith("ELU_STR_ACC"):
return "Accidentelles"
if name_combi.startswith("ELU_STR"):
return "Fondamentales"
raise ValueError(
f"La combinaison '{name_combi}' n'est pas une combinaison ELU "
f"(préfixe attendu : 'ELU_STR' ou 'ELU_STR_ACC')."
)


def min_type_load(self, name_combi: str) -> str:
"""Retourne la classe de durée de chargement la plus courte présente dans une combinaison.

Expand Down
Loading
Loading