Skip to content

fix(ecs): répartir le besoin ecs d'un immeuble au prorata des surfaces des installations (#232) - #233

Merged
michaeldesigaud merged 1 commit into
mainfrom
fix/issue-232-repartition-besoin-ecs-immeuble
Oct 2, 2026
Merged

michaeldesigaud merged 1 commit into
mainfrom
fix/issue-232-repartition-besoin-ecs-immeuble

Conversation

@elliot-redfroggy

Copy link
Copy Markdown
Collaborator

Résumé

Closes #232

Dans src/engine.js (§11.4), le besoin ECS était divisé par 2 dès qu'il y avait plus d'une installation ECS, sauf pour un immeuble dont toutes les installations sont individuelles. Le §11.4 vise un logement équipé de 2 systèmes. Pour un immeuble à plusieurs installations ECS collectives ou mixtes, le moteur de référence répartit le besoin au prorata de la surface habitable desservie par chaque installation.

Règle validée dans l'avis thermique : #232 (comment)

Correctif

  1. src/engine.js : nouveau cas isImmeubleMultiEcs. Il s'applique quand th === 'immeuble', que les installations ne sont pas toutes individuelles, que surface_habitable_immeuble > 0 et que toutes les installation_ecs.donnee_entree.surface_habitable > 0. Dans ce cas, le besoin n'est pas divisé par 2.
    • Repli sur /2 (comportement actuel, §11.4) si une surface manque ou vaut 0, avec un console.warn. Tribu n'a pas de comportement exploitable dans ce cas (il produit des NaN).
  2. src/11_ecs.js : dans ce cas, ratio_besoin_ecs = surface_habitable / surface_habitable_immeuble / (rdim || 1). Le même ratio s'applique à besoin_ecs et à besoin_ecs_depensier. C'est un prorata brut : ni normalisation ni plafonnement quand Σ Sh_ecs ≠ Sh.
  3. rdim : le besoin est calculé par unité dimensionnée (/ rdim), comme dans Tribu. La conso est déjà remultipliée par rdim à l'agrégation : conso.js l.355-356 fixe cle_repartition_ecs = (cle || 1) × (rdim || 1), puis getEcsConso multiplie par cette clé. Aucun autre changement de chaîne n'est donc nécessaire. Le traitement de rdim hors de ce nouveau cas n'est pas modifié.
  4. Inchangés : maison et appartement (/2), cas virtualisés 4/5/32/35/36/37 (cle_repartition_ecs), immeuble tout individuel.

Nouvelle archi src/features/ : pas modifiée. InstallationEcsService.besoinEcsInstallation fait (surface_habitable || Sh)/Sh, mais ajouter / (rdim || 1) ici serait incohérent sans la remultiplication côté conso :

  • la chaîne features/ n'a aucune remultiplication par rdim (aucune occurrence de rdim dans src/features/) ;
  • les pertes récupérées (perte-ecs-recup.service.js) n'en ont pas non plus, alors que Tribu applique Qdw_ind_vc × Rdim (l.374).

Diviser seul sous-estimerait la conso d'un facteur rdim. À traiter avec la migration de la chaîne conso ECS.

Références

  • Méthode 3CL §11.4 (« limité à 2 systèmes différents par logement… Cecs1 = 0,5·Becs·Iecs1 ») : ce texte vise un logement.
  • Guide Tribu TE-211208 p. 24 : ratio = surface habitable desservie / surface du périmètre de calcul. Le 50/50 n'est que le cas particulier SHAB/2.
  • Tribu (Moteur_DPE.dll 2025.11.1.0, DPE.Core/Calcul_batiment.cs) :
    • l.579-593 Calcul_Cecs() : Ratio = Sh_ecs × Rdim / SH ; Becs = Becs1 × Ratio ; Becs /= Rdim (individuelle en immeuble), sinon Ratio = Sh_ecs / SH. Pas de division par 2, pas de normalisation.
    • l.1655-1665 Calcul_Cecs_installation_2() : Cecs1_unité = Becs1 × Ratio × (1-Fecs) × Iecs / Rdim, puis Cecs1_bât += Cecs1_unité × Rdim.
  • Autotests CSTB IC1-0-1/2/3/5/11/12/21/22 : Becs_i / Becs = Sh_ecs_i / SH.

Impact mesuré

Critères corpus : écart ≤ 5 % sur conso_ecs, conso_ch, ep et ges ; mode bug_for_bug_compat + tv_match_optimized.

Jeu DPE OK main OK branche KO→OK OK→KO
Immeubles ≥ 2 installations ECS dont une collective 606 69 306 +241 −4
↳ dpe_immeuble_chauffage_mixte 373 40 211
↳ dpe_immeuble_chauffage_collectif 178 26 77
↳ dpe_immeuble_chauffage_individuel 55 3 18
Maison et appartement (200 multi-ECS + 100 mono-ECS) 300 0 changement (hash complet sortie + donnee_intermediaire ECS)
Fixtures test/fixtures/*.json 31 0 changement
Autotests CSTB (convertis) 50 0 changement

Remarque : le convertisseur des autotests ne produit qu'une installation ECS par cas, il ne teste donc pas le multi-ECS.

Le résultat est identique à la simulation de l'avis thermique (mêmes 306 DPE OK).

DPE passant de OK à KO (4) : le /2 masquait un autre écart, ou ADEME s'écarte de la règle.

  • 2314E3266922M : installation collective conforme (0,4469 = Sh_i/Sh). L'installation individuelle (Sh 150, rdim 30) a un ratio ADEME de 0,0184 contre 0,0006 calculé, soit un autre écart à investiguer.
  • 2362E0245157P : ratios ADEME = Sh_i/Sh exactement (0,2766 et 0,1701). Le /2 compensait un autre écart (écart conso_ecs 50 %), à investiguer.
  • 2567E0137928R : erreur du logiciel, qui applique 0,5 par installation alors que Σ = Sh/2 (230,5 + 230,5 sur 922).
  • 2574E0297333X : ratios ADEME = Sh_i/Sh (0,1667 et 0,6667). Le /2 masquait un autre écart (écart conso_ecs 7,3 %, ep 2,9 %).

Tests

  • src/11_ecs.spec.js : +8 tests. IC1-0-2 (20/155 sur 175 → 0,1143 et 0,8857), Σ < Sh (461/922 → 0,5 sans normalisation), Σ > Sh (sans plafond), immeuble mixte (installation individuelle Sh 800, rdim 13, sur 2400 → 0,02564), rdim absent ou nul, besoin_ecs_depensier au même ratio, priorité sur la virtualisation et sur le cas tout individuel, valeur par défaut. 37/37 ✅, couverture 100 %.
  • src/engine.spec.js : +6 tests. Surfaces renseignées → besoin non divisé et indicateur transmis. Surface d'installation nulle, absente, ou surface immeuble nulle → repli /2 avec avertissement. Appartement avec 2 installations → /2 inchangé. Immeuble tout individuel → inchangé. 47/47 ✅, couverture 100 %.
  • Suite src : 1706 passed / 0 failed (main : 1692 / 0).
  • Suite test/ : 35 échecs, les 35 mêmes que sur main (identifiants ADEME absents, données manquantes) : aucune régression.
  • ESLint et Prettier : OK.

Hors périmètre

  • Formule de repli « immeuble tout individuel » (src/11_ecs.js, branche isImmeubleSystemEcsIndividuels sans nombreAppartements) : elle divise par nombre_logement × nombreAppartements, ce qui est incohérent (et donne une division par 0 quand nombreAppartements est absent). Je n'y ai pas touché.
  • Cas virtualisés 4/5/32/35-37 (cle_repartition_ecs) : sans équivalent dans Tribu, à revoir séparément.
  • Nouvelle archi features/ : alignement de rdim (besoin / rdim et remultiplication de la conso et des pertes récupérées) à faire avec la migration de la chaîne ECS.
  • 2193E1043519Y reste KO et en SORTIR : ADEME applique 7 706 m² à l'installation 76 au lieu des 3 853 m² déclarés.
  • Résidu d'environ 15 % : logiciels appliquant Sh_i/Sh/nombre_logement (versions 2.3/2.4) ou la surface chauffée du chauffage. On ne les suit pas.

PR générée par Hermes.

…s des installations (#232)

Pour un DPE immeuble avec au moins 2 installations ECS dont une collective,
le besoin ECS (conventionnel et dépensier) de chaque installation vaut
Sh_installation / Sh_immeuble / (rdim || 1), au lieu du besoin divisé par 2.
Prorata brut, sans normalisation ni plafonnement (code Tribu
Calcul_batiment.Calcul_Cecs). La consommation reste remultipliée par rdim
dans conso.js (cle_repartition_ecs), comme Tribu (Calcul_Cecs_installation_2).

Repli sur la division par 2 (§11.4) avec avertissement si une surface
d'installation ou la surface de l'immeuble est absente ou nulle.
Maison, appartement, cas virtualisés et immeuble tout individuel inchangés.

Closes #232
@michaeldesigaud
michaeldesigaud self-requested a review October 2, 2026 22:20
@michaeldesigaud michaeldesigaud added the bug Something isn't working label Oct 2, 2026
@michaeldesigaud
michaeldesigaud merged commit 658408a into main Oct 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DPE IMMEUBLE] Besoin ECS divisé par 2 avec plusieurs installations ECS collectives au lieu d'une répartition au prorata des surfaces

2 participants