@open3cl/engine 1.7.2 → 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/3.2.1_mur.js CHANGED
@@ -122,7 +122,7 @@ function tv_umur(di, de, du, pc_id, zc, effetJoule) {
122
122
  }
123
123
  }
124
124
 
125
- function calc_umur0(di, de, du) {
125
+ function calc_umur0(di, de, du, versionDpe) {
126
126
  const umur0_avant = du.umur0_avant;
127
127
  const umur_avant = du.umur_avant;
128
128
 
@@ -166,8 +166,17 @@ function calc_umur0(di, de, du) {
166
166
  }
167
167
  }
168
168
 
169
- // Si présence d'un doublage
170
- if (type_doublage > 2) {
169
+ /**
170
+ * Le doublage NE doit PAS être cumulé à une isolation ITE ou ITI.
171
+ * Il doit uniquement être pris en compte en l'absence d'isolation ITE/ITI (ex: ITR seule, non isolé, inconnu).
172
+ * Types avec ITE ou ITI : 3 (iti), 4 (ite), 6 (iti+ite), 7 (iti+itr), 8 (ite+itr)
173
+ * @see https://github.com/Open3CL/engine/issues/146
174
+ */
175
+ const type_isolation = parseInt(de.enum_type_isolation_id) || 1;
176
+ const hasIteOrIti = versionDpe >= 2.4 && [3, 4, 6, 7, 8].includes(type_isolation);
177
+
178
+ // Si présence d'un doublage et pas d'isolation ITE/ITI
179
+ if (type_doublage > 2 && !hasIteOrIti) {
171
180
  let umur0Doublage;
172
181
 
173
182
  // 3 - doublage indéterminé ou lame d'air inf 15 mm
@@ -212,7 +221,7 @@ function calc_umur0(di, de, du) {
212
221
  di.umur0 = Math.min(2.5, di.umur0);
213
222
  }
214
223
 
215
- export default function calc_mur(mur, zc, pc_id, effetJoule) {
224
+ export default function calc_mur(mur, zc, pc_id, effetJoule, versionDpe) {
216
225
  const de = mur.donnee_entree;
217
226
  const du = {};
218
227
  const di = {};
@@ -228,12 +237,12 @@ export default function calc_mur(mur, zc, pc_id, effetJoule) {
228
237
  const methode_saisie_u = requestInput(de, du, 'methode_saisie_u');
229
238
  switch (methode_saisie_u) {
230
239
  case 'non isolé':
231
- calc_umur0(di, de, du);
240
+ calc_umur0(di, de, du, versionDpe);
232
241
  di.umur = Math.min(di.umur0, 2.5);
233
242
  break;
234
243
  case 'epaisseur isolation saisie justifiée par mesure ou observation':
235
244
  case 'epaisseur isolation saisie justifiée à partir des documents justificatifs autorisés': {
236
- calc_umur0(di, de, du);
245
+ calc_umur0(di, de, du, versionDpe);
237
246
  const epaisseurIsolation = requestInput(de, du, 'epaisseur_isolation', 'int') * 0.01;
238
247
 
239
248
  if (epaisseurIsolation) {
@@ -251,7 +260,7 @@ export default function calc_mur(mur, zc, pc_id, effetJoule) {
251
260
  }
252
261
  case "resistance isolation saisie justifiée observation de l'isolant installé et mesure de son épaisseur":
253
262
  case 'resistance isolation saisie justifiée à partir des documents justificatifs autorisés': {
254
- calc_umur0(di, de, du);
263
+ calc_umur0(di, de, du, versionDpe);
255
264
  const resistanceIsolation = requestInput(de, du, 'resistance_isolation', 'float');
256
265
 
257
266
  if (resistanceIsolation) {
@@ -268,19 +277,19 @@ export default function calc_mur(mur, zc, pc_id, effetJoule) {
268
277
  break;
269
278
  }
270
279
  case 'isolation inconnue (table forfaitaire)':
271
- calc_umur0(di, de, du);
280
+ calc_umur0(di, de, du, versionDpe);
272
281
  tv_umur(di, de, du, pc_id, zc, effetJoule);
273
282
  di.umur = Math.min(di.umur, di.umur0);
274
283
  break;
275
284
  case "année d'isolation différente de l'année de construction saisie justifiée (table forfaitaire)": {
276
- calc_umur0(di, de, du);
285
+ calc_umur0(di, de, du, versionDpe);
277
286
  const pi_id = requestInputID(de, du, 'periode_isolation') || pc_id;
278
287
  tv_umur(di, de, du, pi_id, zc, effetJoule);
279
288
  di.umur = Math.min(di.umur, di.umur0);
280
289
  break;
281
290
  }
282
291
  case 'année de construction saisie (table forfaitaire)': {
283
- calc_umur0(di, de, du);
292
+ calc_umur0(di, de, du, versionDpe);
284
293
  // Si l'année d'isolation est connue, il faut l'utiliser et pas l'année de construction
285
294
  let pi_id = de.enum_periode_isolation_id || pc_id;
286
295
  if (!de.enum_periode_isolation_id) {
package/3.2.1_mur.spec.js CHANGED
@@ -819,3 +819,108 @@ describe('calc_mur - méthode de saisie de U inconnue', () => {
819
819
  warn.mockRestore();
820
820
  });
821
821
  });
822
+
823
+ /**
824
+ * Le doublage n'est plus cumulé à une isolation ITE ou ITI à partir de la version 2.4 du DPE.
825
+ * Les DPE antérieurs (2 à 2.3) ont été établis avec le cumul : on conserve ce comportement.
826
+ * @see https://github.com/Open3CL/engine/issues/146
827
+ */
828
+ describe('calc_mur - doublage et isolation ITE/ITI (#146)', () => {
829
+ /** Umur0 issu de la table forfaitaire mockée. */
830
+ const UMUR0_TABLE = 2;
831
+ /** Umur0 avec doublage type 4 ou 5 cumulé : 1 / (1/2 + 0,21). */
832
+ const UMUR0_AVEC_DOUBLAGE = 1.4084507042253522;
833
+
834
+ /**
835
+ * @param enum_type_isolation_id {string}
836
+ * @param enum_type_doublage_id {string}
837
+ * @return {object}
838
+ */
839
+ const murIsoleAvecDoublage = (enum_type_isolation_id, enum_type_doublage_id = '5') => ({
840
+ donnee_entree: {
841
+ methode_saisie_u: 'epaisseur isolation saisie justifiée par mesure ou observation',
842
+ methode_saisie_u0:
843
+ 'déterminé selon le matériau et épaisseur à partir de la table de valeur forfaitaire',
844
+ enum_materiaux_structure_mur_id: '5',
845
+ epaisseur_structure: 30,
846
+ epaisseur_isolation: 10,
847
+ enum_type_doublage_id,
848
+ enum_type_isolation_id
849
+ }
850
+ });
851
+
852
+ describe('DPE en version 2.4 et supérieure', () => {
853
+ test.each([
854
+ ['iti', '3'],
855
+ ['ite', '4'],
856
+ ['iti+ite', '6'],
857
+ ['iti+itr', '7'],
858
+ ['ite+itr', '8']
859
+ ])("isolation %s : le doublage n'est pas cumulé", (_label, typeIsolation) => {
860
+ const mur = murIsoleAvecDoublage(typeIsolation);
861
+
862
+ calc_mur(mur, 'h1a', '1', '0', 2.4);
863
+
864
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_TABLE, 9);
865
+ });
866
+
867
+ test.each([
868
+ ['inconnu', '1'],
869
+ ['non isolé', '2'],
870
+ ['itr', '5'],
871
+ ["isolé mais type d'isolation inconnu", '9']
872
+ ])('isolation %s : le doublage est cumulé', (_label, typeIsolation) => {
873
+ const mur = murIsoleAvecDoublage(typeIsolation);
874
+
875
+ calc_mur(mur, 'h1a', '1', '0', 2.4);
876
+
877
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_AVEC_DOUBLAGE, 9);
878
+ });
879
+
880
+ test('type_isolation absent : le doublage est cumulé', () => {
881
+ const mur = murIsoleAvecDoublage(undefined);
882
+
883
+ calc_mur(mur, 'h1a', '1', '0', 2.5);
884
+
885
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_AVEC_DOUBLAGE, 9);
886
+ });
887
+ });
888
+
889
+ describe('DPE antérieurs à la version 2.4', () => {
890
+ test.each([[2], [2.1], [2.2], [2.3]])(
891
+ 'version %s : le doublage reste cumulé à une isolation ITI',
892
+ (versionDpe) => {
893
+ const mur = murIsoleAvecDoublage('3');
894
+
895
+ calc_mur(mur, 'h1a', '1', '0', versionDpe);
896
+
897
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_AVEC_DOUBLAGE, 9);
898
+ }
899
+ );
900
+
901
+ test('version absente : le doublage reste cumulé à une isolation ITE', () => {
902
+ const mur = murIsoleAvecDoublage('4');
903
+
904
+ calc_mur(mur, 'h1a', '1', '0');
905
+
906
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_AVEC_DOUBLAGE, 9);
907
+ });
908
+ });
909
+
910
+ test.each([
911
+ ['isolation inconnue (table forfaitaire)'],
912
+ [
913
+ "année d'isolation différente de l'année de construction saisie justifiée (table forfaitaire)"
914
+ ],
915
+ ['année de construction saisie (table forfaitaire)'],
916
+ ['resistance isolation saisie justifiée à partir des documents justificatifs autorisés']
917
+ ])('methode_saisie_u "%s" : la version du DPE est prise en compte', (methode_saisie_u) => {
918
+ const mur = murIsoleAvecDoublage('3');
919
+ mur.donnee_entree.methode_saisie_u = methode_saisie_u;
920
+ mur.donnee_entree.resistance_isolation = 2.5;
921
+
922
+ calc_mur(mur, 'h1a', '1', '0', 2.4);
923
+
924
+ expect(mur.donnee_intermediaire.umur0).toBeCloseTo(UMUR0_TABLE, 9);
925
+ });
926
+ });
package/3_deperdition.js CHANGED
@@ -224,7 +224,12 @@ export default function calc_deperdition(cg, zc, th, effetJoule, dpe, Sh) {
224
224
  const declaredPontsThermiques = structuredClone(pt_list);
225
225
  const vt_list = logement.ventilation_collection.ventilation || [];
226
226
 
227
- mur_list.forEach((mur) => calc_mur(mur, zc, pc, effetJoule));
227
+ /**
228
+ * Version de la méthode appliquée au DPE. Absente des DPE partiels : les calculs qui en
229
+ * dépendent retombent alors sur le comportement historique.
230
+ */
231
+ const versionDpe = parseFloat(dpe.administratif?.enum_version_id);
232
+ mur_list.forEach((mur) => calc_mur(mur, zc, pc, effetJoule, versionDpe));
228
233
  pb_list.forEach((pb) => calc_pb(pb, zc, pc, effetJoule, pb_list));
229
234
  ph_list.forEach((ph) => calc_ph(ph, zc, pc, effetJoule));
230
235
  bv_list.forEach((bv) => calc_bv(bv, zc));
@@ -125,6 +125,7 @@ describe('Upt - déperdition linéique des ponts thermiques', () => {
125
125
 
126
126
  /** Fabrique un DPE minimal avec une enveloppe pré-calculée. */
127
127
  function makeDpe({
128
+ enum_version_id = '2.4',
128
129
  mur = [],
129
130
  pb = [],
130
131
  ph = [],
@@ -141,6 +142,7 @@ function makeDpe({
141
142
  }
142
143
  return {
143
144
  numero_dpe: 'TEST',
145
+ administratif: enum_version_id === null ? undefined : { enum_version_id },
144
146
  logement: {
145
147
  sortie: { deperdition },
146
148
  enveloppe: {
@@ -239,6 +241,51 @@ describe("calc_deperdition - agrégation des déperditions de l'enveloppe", () =
239
241
  expect(calc_ventilation).toHaveBeenCalledTimes(1);
240
242
  });
241
243
 
244
+ /**
245
+ * Certains calculs de Umur dépendent de la version de la méthode appliquée au DPE
246
+ * (cumul du doublage avec une isolation ITE/ITI avant la version 2.4).
247
+ * @see https://github.com/Open3CL/engine/issues/146
248
+ */
249
+ describe('version du DPE transmise au calcul des murs', () => {
250
+ /** @return {object[]} */
251
+ const murCollection = () => [
252
+ {
253
+ donnee_entree: { surface_paroi_opaque: 10, enum_type_adjacence_id: '1' },
254
+ donnee_intermediaire: { umur: 0.5, b: 1 }
255
+ }
256
+ ];
257
+
258
+ test.each([
259
+ ['2.3', 2.3],
260
+ ['2.4', 2.4],
261
+ ['2.5', 2.5]
262
+ ])('enum_version_id "%s" transmis à calc_mur', (enum_version_id, expected) => {
263
+ const dpe = makeDpe({
264
+ enum_version_id,
265
+ mur: murCollection(),
266
+ ventilation: [{ donnee_intermediaire: { hvent: 0, hperm: 0 } }],
267
+ deperdition_mur: 5
268
+ });
269
+
270
+ calc_deperdition({ enum_periode_construction_id: '1' }, 'h1a', 'th', '0', dpe, 100);
271
+
272
+ expect(calc_mur).toHaveBeenCalledWith(expect.anything(), 'h1a', '1', '0', expected);
273
+ });
274
+
275
+ test('bloc administratif absent : calc_mur reçoit NaN et conserve le comportement historique', () => {
276
+ const dpe = makeDpe({
277
+ enum_version_id: null,
278
+ mur: murCollection(),
279
+ ventilation: [{ donnee_intermediaire: { hvent: 0, hperm: 0 } }],
280
+ deperdition_mur: 5
281
+ });
282
+
283
+ calc_deperdition({ enum_periode_construction_id: '1' }, 'h1a', 'th', '0', dpe, 100);
284
+
285
+ expect(calc_mur).toHaveBeenCalledWith(expect.anything(), 'h1a', '1', '0', NaN);
286
+ });
287
+ });
288
+
242
289
  /**
243
290
  * calc_Sdep (surface déperditive transmise à la ventilation) exclut les parois à coefficient
244
291
  * b nul et les parois adjacentes à un local non déperditif. Les parois à déperdition nulle
package/README.md CHANGED
@@ -385,28 +385,28 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
385
385
 
386
386
  <!-- CORPUS:START -->
387
387
 
388
- > **Version `1.6.2`** · branche `main` · généré le 2026-09-18
388
+ > **Version `1.6.2`** · branche `pr-174` · généré le 2026-09-20
389
389
  > Seuil de tolérance **5%**
390
390
 
391
391
  <table>
392
392
  <tr>
393
393
  <td align="center"><strong>9</strong><br/><sub>corpus</sub></td>
394
394
  <td align="center"><strong>89 996</strong><br/><sub>DPE analysés</sub></td>
395
- <td align="center"><strong>59 497</strong><br/><sub>DPE conformes</sub></td>
396
- <td align="center"><strong>66,11 %</strong><br/><sub>réussite globale</sub></td>
395
+ <td align="center"><strong>59 522</strong><br/><sub>DPE conformes</sub></td>
396
+ <td align="center"><strong>66,14 %</strong><br/><sub>réussite globale</sub></td>
397
397
  </tr>
398
398
  </table>
399
399
 
400
400
  | | Corpus | Réussite | | DPE conformes |
401
401
  | :-: | :---------------------------------------------------------------------------------------------------------------------- | ----------: | :--------------------- | -------------: |
402
402
  | 🔴 | **Généraliste**<br/><sub>`corpus_dpe.csv`</sub> | **45,97 %** | `█████████░░░░░░░░░░░` | 4 597 / 10 000 |
403
- | 🟢 | **Appartement · chauffage individuel (2025)**<br/><sub>`dpe_appartement_individuel_chauffage_individuel_2025.csv`</sub> | **91,55 %** | `██████████████████░░` | 9 155 / 10 000 |
404
- | 🟢 | **Logement individuel (2025)**<br/><sub>`dpe_logement_individuel_2025.csv`</sub> | **88,14 %** | `██████████████████░░` | 8 812 / 9 998 |
405
- | 🟢 | **Maison individuelle (2025)**<br/><sub>`dpe_maison_individuelle_2025.csv`</sub> | **87,93 %** | `██████████████████░░` | 8 793 / 10 000 |
406
- | 🟡 | **Immeuble · chauffage individuel**<br/><sub>`dpe_immeuble_chauffage_individuel.csv`</sub> | **73,76 %** | `███████████████░░░░░` | 7 375 / 9 999 |
407
- | 🟡 | **Appartement · chauffage collectif (2025)**<br/><sub>`dpe_appartement_individuel_chauffage_collectif_2025.csv`</sub> | **69,47 %** | `██████████████░░░░░░` | 6 947 / 10 000 |
408
- | 🟡 | **Immeuble · chauffage collectif**<br/><sub>`dpe_immeuble_chauffage_collectif.csv`</sub> | **62,27 %** | `████████████░░░░░░░░` | 6 226 / 9 999 |
409
- | 🔴 | **Immeuble · chauffage mixte**<br/><sub>`dpe_immeuble_chauffage_mixte.csv`</sub> | **48,37 %** | `██████████░░░░░░░░░░` | 4 837 / 10 000 |
403
+ | 🟢 | **Appartement · chauffage individuel (2025)**<br/><sub>`dpe_appartement_individuel_chauffage_individuel_2025.csv`</sub> | **91,62 %** | `██████████████████░░` | 9 162 / 10 000 |
404
+ | 🟢 | **Logement individuel (2025)**<br/><sub>`dpe_logement_individuel_2025.csv`</sub> | **88,16 %** | `██████████████████░░` | 8 814 / 9 998 |
405
+ | 🟢 | **Maison individuelle (2025)**<br/><sub>`dpe_maison_individuelle_2025.csv`</sub> | **87,99 %** | `██████████████████░░` | 8 799 / 10 000 |
406
+ | 🟡 | **Immeuble · chauffage individuel**<br/><sub>`dpe_immeuble_chauffage_individuel.csv`</sub> | **73,78 %** | `███████████████░░░░░` | 7 377 / 9 999 |
407
+ | 🟡 | **Appartement · chauffage collectif (2025)**<br/><sub>`dpe_appartement_individuel_chauffage_collectif_2025.csv`</sub> | **69,51 %** | `██████████████░░░░░░` | 6 951 / 10 000 |
408
+ | 🟡 | **Immeuble · chauffage collectif**<br/><sub>`dpe_immeuble_chauffage_collectif.csv`</sub> | **62,30 %** | `████████████░░░░░░░░` | 6 229 / 9 999 |
409
+ | 🔴 | **Immeuble · chauffage mixte**<br/><sub>`dpe_immeuble_chauffage_mixte.csv`</sub> | **48,38 %** | `██████████░░░░░░░░░░` | 4 838 / 10 000 |
410
410
  | 🔴 | **Individuel généré depuis l'immeuble (2026)**<br/><sub>`dpe_individuel_a_partir_dpe_immeuble_2026.csv`</sub> | **27,55 %** | `██████░░░░░░░░░░░░░░` | 2 755 / 10 000 |
411
411
 
412
412
  <sub>🟢 ≥ 85 % · 🟡 ≥ 60 % · 🔴 < 60 %</sub>
@@ -418,24 +418,24 @@ Ces résultats sont **générés automatiquement** à la fin de `npm run test:co
418
418
 
419
419
  <table>
420
420
  <tr>
421
- <td align="center"><strong>5,61 ms</strong><br/><sub>moyenne</sub></td>
422
- <td align="center"><strong>5,03 ms</strong><br/><sub>médiane</sub></td>
423
- <td align="center"><strong>0,11 ms</strong><br/><sub>min</sub></td>
424
- <td align="center"><strong>705,8 ms</strong><br/><sub>max</sub></td>
421
+ <td align="center"><strong>5,23 ms</strong><br/><sub>moyenne</sub></td>
422
+ <td align="center"><strong>4,61 ms</strong><br/><sub>médiane</sub></td>
423
+ <td align="center"><strong>0,10 ms</strong><br/><sub>min</sub></td>
424
+ <td align="center"><strong>577,0 ms</strong><br/><sub>max</sub></td>
425
425
  </tr>
426
426
  </table>
427
427
 
428
428
  | Corpus | Moyenne | Médiane | Min | Max | p95 | p99 |
429
429
  | :--------------------------------------------- | ------: | ------: | ------: | -------: | ------: | ------: |
430
- | **Généraliste** | 4,50 ms | 4,09 ms | 0,20 ms | 34,8 ms | 8,12 ms | 11,3 ms |
431
- | **Appartement · chauffage individuel (2025)** | 3,71 ms | 3,46 ms | 1,32 ms | 26,1 ms | 6,22 ms | 7,99 ms |
432
- | **Logement individuel (2025)** | 5,30 ms | 4,84 ms | 1,52 ms | 42,5 ms | 9,73 ms | 13,2 ms |
433
- | **Maison individuelle (2025)** | 6,54 ms | 6,02 ms | 1,71 ms | 54,5 ms | 11,6 ms | 16,4 ms |
434
- | **Immeuble · chauffage individuel** | 7,17 ms | 6,22 ms | 0,11 ms | 137,7 ms | 14,3 ms | 22,3 ms |
435
- | **Appartement · chauffage collectif (2025)** | 3,98 ms | 3,76 ms | 1,22 ms | 37,6 ms | 6,35 ms | 8,00 ms |
436
- | **Immeuble · chauffage collectif** | 6,40 ms | 5,58 ms | 0,15 ms | 101,0 ms | 12,1 ms | 21,2 ms |
437
- | **Immeuble · chauffage mixte** | 6,01 ms | 5,01 ms | 0,22 ms | 705,8 ms | 12,4 ms | 19,8 ms |
438
- | **Individuel généré depuis l'immeuble (2026)** | 6,89 ms | 6,27 ms | 1,52 ms | 65,1 ms | 13,0 ms | 19,7 ms |
430
+ | **Généraliste** | 4,37 ms | 3,96 ms | 0,22 ms | 35,5 ms | 7,93 ms | 10,8 ms |
431
+ | **Appartement · chauffage individuel (2025)** | 3,49 ms | 3,20 ms | 1,13 ms | 30,2 ms | 6,09 ms | 7,79 ms |
432
+ | **Logement individuel (2025)** | 4,96 ms | 4,38 ms | 1,34 ms | 43,1 ms | 9,48 ms | 12,9 ms |
433
+ | **Maison individuelle (2025)** | 5,88 ms | 5,34 ms | 1,68 ms | 47,0 ms | 10,5 ms | 14,2 ms |
434
+ | **Immeuble · chauffage individuel** | 6,66 ms | 5,73 ms | 0,10 ms | 83,7 ms | 13,6 ms | 21,0 ms |
435
+ | **Appartement · chauffage collectif (2025)** | 4,09 ms | 3,75 ms | 1,26 ms | 37,7 ms | 6,88 ms | 9,51 ms |
436
+ | **Immeuble · chauffage collectif** | 6,04 ms | 5,23 ms | 0,15 ms | 148,9 ms | 11,5 ms | 21,3 ms |
437
+ | **Immeuble · chauffage mixte** | 5,79 ms | 4,77 ms | 0,18 ms | 577,0 ms | 12,4 ms | 20,2 ms |
438
+ | **Individuel généré depuis l'immeuble (2026)** | 5,82 ms | 5,08 ms | 1,65 ms | 71,8 ms | 11,1 ms | 16,9 ms |
439
439
 
440
440
  <sub>La moyenne est tirée vers le haut par les DPE collectifs, dont le coût atteint plusieurs
441
441
  dizaines de fois la médiane : c’est la médiane qui décrit le cas courant, et p95/p99 le cas
package/engine.js CHANGED
@@ -33,7 +33,7 @@ import getFicheTechnique from './ficheTechnique.js';
33
33
  import { ProductionENR } from './16.2_production_enr.js';
34
34
  import DpeSanitizerService from './dpe-sanitizer.service.js';
35
35
 
36
- const LIB_VERSION = '1.7.2';
36
+ const LIB_VERSION = '1.7.3';
37
37
 
38
38
  const dpeSanitizerService = new DpeSanitizerService();
39
39
 
@@ -129,20 +129,29 @@ export class DeperditionMurService extends DeperditionService {
129
129
  }
130
130
 
131
131
  /**
132
- * Pour l’ensemble des parois, la présence d’un doublage apporte une résistance thermique supplémentaire
132
+ * Pour l’ensemble des parois, la présence d’un doublage apporte une résistance thermique supplémentaire.
133
+ * Cependant, lorsqu'une isolation ITE ou ITI est présente, le doublage NE doit PAS être cumulé.
134
+ * Le doublage n'est pris en compte que si aucune isolation ITE/ITI n'est appliquée.
135
+ * Types d'isolation avec ITE ou ITI : 3 (iti), 4 (ite), 6 (iti+ite), 7 (iti+itr), 8 (ite+itr)
136
+ * @see https://github.com/Open3CL/engine/issues/146
133
137
  */
134
- switch (murDE.enum_type_doublage_id) {
135
- case '3':
136
- // doublage indéterminé ou lame d'air inf 15 mm
137
- umur0 = 1 / (1 / umur0 + 0.1);
138
- break;
139
- case '4': // doublage indéterminé ou lame d'air sup 15 mm
140
- case '5': // doublage connu (plâtre brique bois)
141
- umur0 = 1 / (1 / umur0 + 0.21);
142
- break;
143
- default:
144
- // absence de doublage ou inconnu
145
- break;
138
+ const typeIsolation = parseInt(murDE.enum_type_isolation_id) || 1;
139
+ const hasIteOrIti = [3, 4, 6, 7, 8].includes(typeIsolation);
140
+
141
+ if (!hasIteOrIti) {
142
+ switch (murDE.enum_type_doublage_id) {
143
+ case '3':
144
+ // doublage indéterminé ou lame d'air inf 15 mm
145
+ umur0 = 1 / (1 / umur0 + 0.1);
146
+ break;
147
+ case '4': // doublage indéterminé ou lame d'air sup 15 mm
148
+ case '5': // doublage connu (plâtre brique bois)
149
+ umur0 = 1 / (1 / umur0 + 0.21);
150
+ break;
151
+ default:
152
+ // absence de doublage ou inconnu
153
+ break;
154
+ }
146
155
  }
147
156
 
148
157
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open3cl/engine",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
4
4
  "description": "Open Source 3CL-DPE engine",
5
5
  "main": "index.js",
6
6
  "directories": {