@open3cl/engine 1.0.6 → 1.0.8

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.
Files changed (72) hide show
  1. package/11_nadeq.spec.js +3 -2
  2. package/16.2_production_enr.spec.js +1 -0
  3. package/3.2.1_mur.spec.js +1 -0
  4. package/3.2.2_plancher_bas.spec.js +1 -0
  5. package/3.3_baie_vitree.spec.js +1 -0
  6. package/6.1_apport_gratuit.spec.js +1 -0
  7. package/7_inertie.spec.js +4 -3
  8. package/9_chauffage.spec.js +1 -0
  9. package/9_conso_ch.spec.js +1 -0
  10. package/9_generateur_ch.spec.js +1 -0
  11. package/conso.spec.js +1 -0
  12. package/core/assets/domain/synchronize-assets.spec.js +9 -9
  13. package/core/assets/domain/synchronize-c1-tables.spec.js +4 -4
  14. package/core/assets/domain/synchronize-dpe-ges-limit-values-tables.spec.js +6 -6
  15. package/core/assets/domain/synchronize-enum-tables.spec.js +10 -10
  16. package/core/assets/domain/synchronize-solicitations-tables.spec.js +6 -6
  17. package/core/assets/domain/synchronize-valeur-tables.spec.js +14 -14
  18. package/core/file/infrastructure/adapter/file.store.spec.js +5 -4
  19. package/core/tv/infrastructure/tvs.store.spec.js +3 -2
  20. package/core/util/infrastructure/object-util.spec.js +2 -1
  21. package/core/util/logger/log-service.js +47 -0
  22. package/features/dpe/domain/models/baie-ets.model.ts +12 -0
  23. package/features/dpe/domain/models/baie-vitree.model.ts +97 -0
  24. package/features/dpe/domain/models/climatisation.model.ts +25 -0
  25. package/features/dpe/domain/models/dpe.model.ts +194 -0
  26. package/features/dpe/domain/models/ets.model.ts +19 -0
  27. package/features/dpe/domain/models/installation-chauffage.model.ts +101 -0
  28. package/features/dpe/domain/models/installation-ecs.model.ts +76 -0
  29. package/features/dpe/domain/models/mur.model.ts +37 -0
  30. package/features/dpe/domain/models/plancher-bas.model.ts +38 -0
  31. package/features/dpe/domain/models/plancher-haut.model.ts +33 -0
  32. package/features/dpe/domain/models/pont-thermique.model.ts +21 -0
  33. package/features/dpe/domain/models/porte.model.ts +31 -0
  34. package/features/dpe/domain/models/production-elec-enr.model.ts +27 -0
  35. package/features/dpe/domain/models/sortie.model.ts +178 -0
  36. package/features/dpe/domain/models/type-habitation.model.js +8 -0
  37. package/features/dpe/domain/models/type-ventilation.model.js +8 -0
  38. package/features/dpe/domain/models/ventilation.model.ts +33 -0
  39. package/features/dpe/infrastructure/baieVitreeTv.store.js +292 -0
  40. package/features/dpe/infrastructure/baieVitreeTv.store.spec.js +352 -0
  41. package/features/dpe/infrastructure/tv.store.js +356 -0
  42. package/features/dpe/infrastructure/tv.store.spec.js +607 -0
  43. package/features/engine/domain/constants.js +1 -0
  44. package/features/engine/domain/contexte.builder.js +140 -0
  45. package/features/engine/domain/contexte.builder.spec.js +152 -0
  46. package/features/engine/domain/engine.service.js +139 -0
  47. package/features/engine/domain/engine.service.spec.js +7 -0
  48. package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.js +292 -0
  49. package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +484 -0
  50. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.js +278 -0
  51. package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +282 -0
  52. package/features/engine/domain/enveloppe/deperdition.service.js +101 -0
  53. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.js +168 -0
  54. package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +345 -0
  55. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.js +169 -0
  56. package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +200 -0
  57. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.js +136 -0
  58. package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +211 -0
  59. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.js +56 -0
  60. package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +116 -0
  61. package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.js +338 -0
  62. package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.spec.js +442 -0
  63. package/features/engine/domain/models/contexte.model.ts +10 -0
  64. package/features/engine/domain/models/deperdition.model.ts +8 -0
  65. package/features/normalizer/domain/dpe-normalizer.service.js +24 -0
  66. package/features/normalizer/domain/dpe-normalizer.service.spec.js +3 -0
  67. package/ficheTechnique.spec.js +4 -3
  68. package/output.js +1 -0
  69. package/package.json +9 -8
  70. package/tv-v2.js +79121 -0
  71. package/utils.js +2 -2
  72. package/utils.spec.js +4 -3
@@ -0,0 +1,278 @@
1
+ import { inject } from 'dioma';
2
+ import { DeperditionMurService } from './mur/deperdition-mur.service.js';
3
+ import { DeperditionPorteService } from './porte/deperdition-porte.service.js';
4
+ import { DeperditionPlancherBasService } from './plancher_bas/deperdition-plancher-bas.service.js';
5
+ import { DeperditionPlancherHautService } from './plancher_haut/deperdition-plancher-haut.service.js';
6
+ import { DeperditionVentilationService } from './ventilation/deperdition-ventilation.service.js';
7
+ import { DeperditionBaieVitreeService } from './baie_vitree/deperdition-baie-vitree.service.js';
8
+
9
+ /**
10
+ * Calcul des déperditions de l’enveloppe
11
+ * @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021) chapitre 3
12
+ */
13
+ export class DeperditionEnveloppeService {
14
+ /**
15
+ * @type {DeperditionMurService}
16
+ */
17
+ #deperditionMurService;
18
+
19
+ /**
20
+ * @type {DeperditionPorteService}
21
+ */
22
+ #deperditionPorteService;
23
+
24
+ /**
25
+ * @type {DeperditionPlancherBasService}
26
+ */
27
+ #deperditionPlancherBasService;
28
+
29
+ /**
30
+ * @type {DeperditionPlancherHautService}
31
+ */
32
+ #deperditionPlancherHautService;
33
+
34
+ /**
35
+ * @type {DeperditionBaieVitreeService}
36
+ */
37
+ #deperditionBaieVitreeService;
38
+
39
+ /**
40
+ * @type {DeperditionVentilationService}
41
+ */
42
+ #deperditionVentilationService;
43
+
44
+ /**
45
+ * @type {number}
46
+ */
47
+ #surfaceDeperditive;
48
+
49
+ /**
50
+ * @type {number}
51
+ */
52
+ #surfaceIsolee;
53
+
54
+ /**
55
+ * @type {number}
56
+ */
57
+ #surfaceNonIsolee;
58
+
59
+ /**
60
+ * @type {number}
61
+ */
62
+ #surfaceMenuiserieAvecJoint;
63
+
64
+ /**
65
+ * @type {number}
66
+ */
67
+ #surfaceMenuiserieSansJoint;
68
+
69
+ /**
70
+ *
71
+ * @param deperditionMurService {DeperditionMurService}
72
+ * @param deperditionPorteService {DeperditionPorteService}
73
+ * @param deperditionPlancherBasService {DeperditionPlancherBasService}
74
+ * @param deperditionPlancherHautService {DeperditionPlancherHautService}
75
+ * @param deperditionBaieVitreeService {DeperditionBaieVitreeService}
76
+ * @param deperditionVentilationService {DeperditionVentilationService}
77
+ */
78
+ constructor(
79
+ deperditionMurService = inject(DeperditionMurService),
80
+ deperditionPorteService = inject(DeperditionPorteService),
81
+ deperditionPlancherBasService = inject(DeperditionPlancherBasService),
82
+ deperditionPlancherHautService = inject(DeperditionPlancherHautService),
83
+ deperditionBaieVitreeService = inject(DeperditionBaieVitreeService),
84
+ deperditionVentilationService = inject(DeperditionVentilationService)
85
+ ) {
86
+ this.#deperditionMurService = deperditionMurService;
87
+ this.#deperditionPorteService = deperditionPorteService;
88
+ this.#deperditionPlancherBasService = deperditionPlancherBasService;
89
+ this.#deperditionPlancherHautService = deperditionPlancherHautService;
90
+ this.#deperditionBaieVitreeService = deperditionBaieVitreeService;
91
+ this.#deperditionVentilationService = deperditionVentilationService;
92
+ this.#surfaceDeperditive = 0;
93
+ this.#surfaceIsolee = 0;
94
+ this.#surfaceNonIsolee = 0;
95
+ this.#surfaceMenuiserieAvecJoint = 0;
96
+ this.#surfaceMenuiserieSansJoint = 0;
97
+ }
98
+
99
+ /**
100
+ * Calcul des déperditions de l’enveloppe
101
+ * @param ctx {Contexte}
102
+ * @param logement {Logement}
103
+ * @returns {{hvent: number, hperm: number, deperdition_renouvellement_air: number, deperdition_mur: number, deperdition_plancher_bas: number, deperdition_plancher_haut: number, deperdition_baie_vitree: number, deperdition_porte: number, deperdition_pont_thermique: number, deperdition_enveloppe: number}}
104
+ */
105
+ deperditions(ctx, logement) {
106
+ const GV = this.#gv(ctx, logement.enveloppe);
107
+ const ventilation = this.#ventilation(ctx, logement);
108
+ return {
109
+ ...GV,
110
+ ...ventilation,
111
+ ...{
112
+ deperdition_enveloppe:
113
+ GV.deperdition_mur +
114
+ GV.deperdition_plancher_bas +
115
+ GV.deperdition_plancher_haut +
116
+ GV.deperdition_baie_vitree +
117
+ GV.deperdition_porte +
118
+ GV.deperdition_pont_thermique +
119
+ ventilation.hvent +
120
+ ventilation.hperm
121
+ }
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Calcul des déperditions de l’enveloppe GV
127
+ *
128
+ * @param ctx {Contexte}
129
+ * @param enveloppe {Enveloppe}
130
+ *
131
+ * @return {Deperdition}
132
+ */
133
+ #gv(ctx, enveloppe) {
134
+ this.#surfaceDeperditive = 0;
135
+ this.#surfaceIsolee = 0;
136
+ this.#surfaceNonIsolee = 0;
137
+ this.#surfaceMenuiserieAvecJoint = 0;
138
+ this.#surfaceMenuiserieSansJoint = 0;
139
+
140
+ /**
141
+ * @type {Deperdition}
142
+ */
143
+ const deperditions = {
144
+ deperdition_mur: 0,
145
+ deperdition_plancher_bas: 0,
146
+ deperdition_plancher_haut: 0,
147
+ deperdition_baie_vitree: 0,
148
+ deperdition_porte: 0
149
+ };
150
+
151
+ enveloppe.mur_collection.mur?.forEach((m) => {
152
+ m.donnee_intermediaire = this.#deperditionMurService.execute(ctx, m.donnee_entree);
153
+ deperditions.deperdition_mur +=
154
+ m.donnee_intermediaire.b *
155
+ m.donnee_entree.surface_paroi_opaque *
156
+ m.donnee_intermediaire.umur;
157
+
158
+ if (m.donnee_intermediaire.b > 0) {
159
+ // Paroi déperditive si b != 0 et adjacence != 'local non déperditif'
160
+ if (m.donnee_entree.enum_type_adjacence_id !== '22') {
161
+ this.#surfaceDeperditive += m.donnee_entree.surface_paroi_opaque;
162
+ }
163
+ // Surface isolée si b != 0 et type d'isolation != 'inconnu' et != 'non isolé'
164
+ if (['1', '2'].includes(m.donnee_entree.enum_type_isolation_id)) {
165
+ this.#surfaceNonIsolee += m.donnee_entree.surface_paroi_opaque;
166
+ } else {
167
+ this.#surfaceIsolee += m.donnee_entree.surface_paroi_opaque;
168
+ }
169
+ }
170
+ });
171
+
172
+ enveloppe.porte_collection.porte?.forEach((p) => {
173
+ p.donnee_intermediaire = this.#deperditionPorteService.execute(ctx, p.donnee_entree);
174
+ deperditions.deperdition_porte +=
175
+ p.donnee_intermediaire.b * p.donnee_entree.surface_porte * p.donnee_intermediaire.uporte;
176
+
177
+ // Surface de porte déperditive si b != 0
178
+ if (p.donnee_intermediaire.b > 0) {
179
+ this.#surfaceDeperditive += p.donnee_entree.surface_porte;
180
+ }
181
+ // Surface de porte avec ou sans joint
182
+ if (p.donnee_entree.presence_joint) {
183
+ this.#surfaceMenuiserieAvecJoint += p.donnee_entree.surface_porte;
184
+ } else {
185
+ this.#surfaceMenuiserieSansJoint += p.donnee_entree.surface_porte;
186
+ }
187
+ });
188
+
189
+ const plancherBas = enveloppe.plancher_bas_collection.plancher_bas || [];
190
+ plancherBas?.forEach((pb) => {
191
+ pb.donnee_intermediaire = this.#deperditionPlancherBasService.execute(
192
+ ctx,
193
+ pb.donnee_entree,
194
+ plancherBas
195
+ );
196
+ deperditions.deperdition_plancher_bas +=
197
+ pb.donnee_intermediaire.b *
198
+ pb.donnee_entree.surface_paroi_opaque *
199
+ pb.donnee_intermediaire.upb_final;
200
+ });
201
+
202
+ enveloppe.plancher_haut_collection.plancher_haut?.forEach((ph) => {
203
+ ph.donnee_intermediaire = this.#deperditionPlancherHautService.execute(ctx, ph.donnee_entree);
204
+ deperditions.deperdition_plancher_haut +=
205
+ ph.donnee_intermediaire.b *
206
+ ph.donnee_entree.surface_paroi_opaque *
207
+ ph.donnee_intermediaire.uph;
208
+
209
+ if (ph.donnee_intermediaire.b > 0) {
210
+ // Plancher déperditif si b != 0 et adjacence != 'local non déperditif'
211
+ if (ph.donnee_entree.enum_type_adjacence_id !== '22') {
212
+ this.#surfaceDeperditive += ph.donnee_entree.surface_paroi_opaque;
213
+ }
214
+ // Surface isolée si b != 0 et type d'isolation != 'inconnu' et != 'non isolé'
215
+ if (['1', '2'].includes(ph.donnee_entree.enum_type_isolation_id)) {
216
+ this.#surfaceNonIsolee += ph.donnee_entree.surface_paroi_opaque;
217
+ } else {
218
+ this.#surfaceIsolee += ph.donnee_entree.surface_paroi_opaque;
219
+ }
220
+ }
221
+ });
222
+
223
+ enveloppe.baie_vitree_collection.baie_vitree?.forEach((bv) => {
224
+ bv.donnee_intermediaire = this.#deperditionBaieVitreeService.execute(ctx, bv);
225
+ deperditions.deperdition_baie_vitree +=
226
+ bv.donnee_intermediaire.b *
227
+ bv.donnee_entree.surface_totale_baie *
228
+ bv.donnee_intermediaire.u_menuiserie;
229
+
230
+ // Surface de baie vitrée déperditive si b != 0
231
+ if (bv.donnee_intermediaire.b > 0) {
232
+ this.#surfaceDeperditive += bv.donnee_entree.surface_totale_baie;
233
+ }
234
+ // Surface de baie vitrée avec ou sans joint
235
+ if (bv.donnee_entree.presence_joint) {
236
+ this.#surfaceMenuiserieAvecJoint += bv.donnee_entree.surface_totale_baie;
237
+ } else {
238
+ this.#surfaceMenuiserieSansJoint += bv.donnee_entree.surface_totale_baie;
239
+ }
240
+ });
241
+
242
+ return deperditions;
243
+ }
244
+
245
+ /**
246
+ * Calcul des déperditions par la ventilation
247
+ *
248
+ * @param ctx {Contexte}
249
+ * @param logement {Logement}
250
+ *
251
+ * @return {Deperdition}
252
+ */
253
+ #ventilation(ctx, logement) {
254
+ /**
255
+ * @type {Deperdition}
256
+ */
257
+ const deperditions = {
258
+ hperm: 0,
259
+ hvent: 0
260
+ };
261
+
262
+ logement.ventilation_collection.ventilation?.forEach((ventilation) => {
263
+ ventilation.donnee_intermediaire = this.#deperditionVentilationService.execute(
264
+ ctx,
265
+ ventilation.donnee_entree,
266
+ this.#surfaceDeperditive,
267
+ this.#surfaceIsolee,
268
+ this.#surfaceNonIsolee,
269
+ this.#surfaceMenuiserieAvecJoint,
270
+ this.#surfaceMenuiserieSansJoint
271
+ );
272
+ deperditions.hvent += ventilation.donnee_intermediaire.hvent;
273
+ deperditions.hperm += ventilation.donnee_intermediaire.hperm;
274
+ });
275
+
276
+ return deperditions;
277
+ }
278
+ }
@@ -0,0 +1,282 @@
1
+ import { DeperditionEnveloppeService } from './deperdition-enveloppe.service.js';
2
+ import corpus from '../../../../../test/corpus-sano.json';
3
+ import { getAdemeFileJson } from '../../../../../test/test-helpers.js';
4
+ import { ContexteBuilder } from '../contexte.builder.js';
5
+ import { DeperditionPlancherBasService } from './plancher_bas/deperdition-plancher-bas.service.js';
6
+ import { DeperditionMurService } from './mur/deperdition-mur.service.js';
7
+ import { DeperditionPorteService } from './porte/deperdition-porte.service.js';
8
+ import { DeperditionPlancherHautService } from './plancher_haut/deperdition-plancher-haut.service.js';
9
+ import { DpeNormalizerService } from '../../../normalizer/domain/dpe-normalizer.service.js';
10
+ import { TvStore } from '../../../dpe/infrastructure/tv.store.js';
11
+ import { beforeEach, describe, expect, test } from 'vitest';
12
+ import b from '../../../../3.1_b.js';
13
+
14
+ /** @type {DeperditionPorteService} **/
15
+ let deperditionPorteService;
16
+
17
+ /** @type {DeperditionMurService} **/
18
+ let deperditionMurService;
19
+
20
+ /** @type {DeperditionPlancherBasService} **/
21
+ let deperditionPlancherBasService;
22
+
23
+ /** @type {DeperditionPlancherHautService} **/
24
+ let deperditionPlancherHautService;
25
+
26
+ /** @type {DpeNormalizerService} **/
27
+ let normalizerService;
28
+
29
+ /** @type {ContexteBuilder} **/
30
+ let contexteBuilder;
31
+
32
+ /** @type {TvStore} **/
33
+ let tvStore;
34
+
35
+ /** @type {DeperditionEnveloppeService} **/
36
+ let service;
37
+
38
+ describe('Calcul des déperditions', () => {
39
+ beforeEach(() => {
40
+ tvStore = new TvStore();
41
+ deperditionPorteService = new DeperditionPorteService(tvStore);
42
+ deperditionMurService = new DeperditionMurService(tvStore);
43
+ deperditionPlancherBasService = new DeperditionPlancherBasService(tvStore);
44
+ deperditionPlancherHautService = new DeperditionPlancherHautService(tvStore);
45
+ normalizerService = new DpeNormalizerService();
46
+ contexteBuilder = new ContexteBuilder();
47
+
48
+ service = new DeperditionEnveloppeService(
49
+ deperditionMurService,
50
+ deperditionPorteService,
51
+ deperditionPlancherBasService,
52
+ deperditionPlancherHautService
53
+ );
54
+ });
55
+
56
+ describe('Détermination du coefficient de réduction des déperditions b', () => {
57
+ test.each([
58
+ { enumTypeAdjacenceId: '1', label: 'extérieur', bExpected: 1 },
59
+ { enumTypeAdjacenceId: '2', label: 'paroi enterrée', bExpected: 1 },
60
+ { enumTypeAdjacenceId: '3', label: 'vide sanitaire', bExpected: 1 },
61
+ {
62
+ enumTypeAdjacenceId: '4',
63
+ label: "bâtiment ou local à usage autre que d'habitation",
64
+ bExpected: 0.2
65
+ },
66
+ { enumTypeAdjacenceId: '5', label: 'terre-plein', bExpected: 1 },
67
+ { enumTypeAdjacenceId: '6', label: 'sous-sol non chauffé', bExpected: 1 },
68
+ {
69
+ enumTypeAdjacenceId: '7',
70
+ enumCfgIsolationLncId: '1',
71
+ label: 'locaux non chauffés non accessible',
72
+ bExpected: 0.95
73
+ },
74
+ {
75
+ enumTypeAdjacenceId: '8',
76
+ surfaceAiu: 14.75,
77
+ surfaceAue: 300,
78
+ enumCfgIsolationLncId: '2',
79
+ label: 'garage',
80
+ bExpected: 0.9
81
+ },
82
+ {
83
+ enumTypeAdjacenceId: '9',
84
+ surfaceAiu: 8.14,
85
+ surfaceAue: 22.8,
86
+ enumCfgIsolationLncId: '4',
87
+ label: 'cellier',
88
+ bExpected: 0.95
89
+ },
90
+ {
91
+ enumTypeAdjacenceId: '10',
92
+ surfaceAiu: 8.14,
93
+ surfaceAue: 22.8,
94
+ enumCfgIsolationLncId: '9',
95
+ label: 'espace tampon solarisé (véranda,loggia fermée)',
96
+ bExpected: undefined
97
+ },
98
+ {
99
+ enumTypeAdjacenceId: '10',
100
+ surfaceAiu: 8.14,
101
+ surfaceAue: 22.8,
102
+ zoneClimatiqueId: '5',
103
+ enumCfgIsolationLncId: '9',
104
+ label: 'espace tampon solarisé (véranda,loggia fermée)',
105
+ bExpected: 0.85
106
+ },
107
+ {
108
+ enumTypeAdjacenceId: '11',
109
+ surfaceAiu: 50.2,
110
+ surfaceAue: 60,
111
+ enumCfgIsolationLncId: '4',
112
+ label: 'comble fortement ventilé',
113
+ bExpected: 0.95
114
+ },
115
+ {
116
+ enumTypeAdjacenceId: '12',
117
+ surfaceAiu: 74,
118
+ surfaceAue: 110,
119
+ enumCfgIsolationLncId: '4',
120
+ label: 'comble faiblement ventilé',
121
+ bExpected: 0.95
122
+ },
123
+ {
124
+ enumTypeAdjacenceId: '13',
125
+ surfaceAiu: 30,
126
+ surfaceAue: 45,
127
+ enumCfgIsolationLncId: '2',
128
+ label: 'comble très faiblement ventilé',
129
+ bExpected: 0.65
130
+ },
131
+ {
132
+ enumTypeAdjacenceId: '14',
133
+ surfaceAiu: 22,
134
+ surfaceAue: 15,
135
+ enumCfgIsolationLncId: '2',
136
+ label: "circulation sans ouverture directe sur l'extérieur",
137
+ bExpected: 0.35
138
+ },
139
+ {
140
+ enumTypeAdjacenceId: '15',
141
+ surfaceAiu: 20,
142
+ surfaceAue: 2.5,
143
+ enumCfgIsolationLncId: '2',
144
+ label: "circulation avec ouverture directe sur l'extérieur",
145
+ bExpected: 0.15
146
+ },
147
+ {
148
+ enumTypeAdjacenceId: '16',
149
+ surfaceAiu: 120,
150
+ surfaceAue: 300,
151
+ enumCfgIsolationLncId: '3',
152
+ label: 'circulation avec bouche ou gaine de désenfumage ouverte en permanence',
153
+ bExpected: 0.7
154
+ },
155
+ {
156
+ enumTypeAdjacenceId: '17',
157
+ label: "hall d'entrée avec dispositif de fermeture automatique",
158
+ bExpected: 0
159
+ },
160
+ {
161
+ enumTypeAdjacenceId: '18',
162
+ surfaceAiu: 335.22,
163
+ surfaceAue: 29.18,
164
+ enumCfgIsolationLncId: '2',
165
+ label: "hall d'entrée sans dispositif de fermeture automatique",
166
+ bExpected: 0.15
167
+ },
168
+ {
169
+ enumTypeAdjacenceId: '19',
170
+ surfaceAiu: 49,
171
+ surfaceAue: 65,
172
+ enumCfgIsolationLncId: '2',
173
+ label: 'garage privé collectif',
174
+ bExpected: 0.7
175
+ },
176
+ {
177
+ enumTypeAdjacenceId: '20',
178
+ label: "local tertiaire à l'intérieur de l'immeuble en contact avec l'appartement",
179
+ bExpected: 0.2
180
+ },
181
+ {
182
+ enumTypeAdjacenceId: '21',
183
+ surfaceAiu: 4.94,
184
+ surfaceAue: 8.8,
185
+ enumCfgIsolationLncId: '2',
186
+ label: 'autres dépendances',
187
+ bExpected: 0.75
188
+ },
189
+ {
190
+ enumTypeAdjacenceId: '22',
191
+ label: "local non déperditif (local à usage d'habitation chauffé)",
192
+ bExpected: 0
193
+ }
194
+ ])(
195
+ '$label (id:$enumTypeAdjacenceId)',
196
+ ({
197
+ enumTypeAdjacenceId,
198
+ surfaceAiu = undefined,
199
+ surfaceAue = undefined,
200
+ zoneClimatiqueId = undefined,
201
+ enumCfgIsolationLncId = undefined,
202
+ bExpected
203
+ }) => {
204
+ const data = {
205
+ enumTypeAdjacenceId,
206
+ surfaceAiu,
207
+ surfaceAue,
208
+ enumCfgIsolationLncId,
209
+ zoneClimatiqueId
210
+ };
211
+
212
+ const b = deperditionMurService.b(data);
213
+ expect(b).toBe(bExpected);
214
+ }
215
+ );
216
+ });
217
+
218
+ describe.skip('Benchmark', () => {
219
+ test('reworked', () => {
220
+ const data = {
221
+ enumTypeAdjacenceId: '8',
222
+ surfaceAiu: 2.82,
223
+ surfaceAue: 300,
224
+ enumCfgIsolationLncId: '2',
225
+ label: 'garage'
226
+ };
227
+
228
+ for (let i = 0; i < 1000; i++) {
229
+ const b = deperditionMurService.b(data);
230
+ expect(b).toBe(0.9);
231
+ }
232
+ });
233
+
234
+ test('legacy', () => {
235
+ const di = { b: undefined };
236
+ const de = {
237
+ enum_type_adjacence_id: '8',
238
+ surface_aiu: 2.82,
239
+ surface_aue: 300,
240
+ enum_cfg_isolation_lnc_id: '2'
241
+ };
242
+ const du = {};
243
+ const zc = '1';
244
+
245
+ for (let i = 0; i < 1000; i++) {
246
+ b(di, de, du, zc);
247
+ expect(di.b).toBe(0.9);
248
+ }
249
+ });
250
+ });
251
+
252
+ describe("Test d'intégration de calcul des deperditions", () => {
253
+ test.each(corpus)('deperditions pour dpe %s', (ademeId) => {
254
+ let dpeRequest = getAdemeFileJson(ademeId);
255
+ dpeRequest = normalizerService.normalize(dpeRequest);
256
+
257
+ /** @type {Contexte} */
258
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
259
+ /** @type {Logement} */
260
+ const logement = dpeRequest.logement;
261
+ /** @type {Deperdition} */
262
+ const deperditions = service.deperditions(ctx, logement);
263
+
264
+ expect(deperditions.deperdition_mur).toBeCloseTo(
265
+ dpeRequest.logement.sortie.deperdition.deperdition_mur,
266
+ 1
267
+ );
268
+ expect(deperditions.deperdition_porte).toBeCloseTo(
269
+ dpeRequest.logement.sortie.deperdition.deperdition_porte,
270
+ 1
271
+ );
272
+ expect(deperditions.deperdition_plancher_bas).toBeCloseTo(
273
+ dpeRequest.logement.sortie.deperdition.deperdition_plancher_bas,
274
+ 1
275
+ );
276
+ expect(deperditions.deperdition_plancher_haut).toBeCloseTo(
277
+ dpeRequest.logement.sortie.deperdition.deperdition_plancher_haut,
278
+ 1
279
+ );
280
+ });
281
+ });
282
+ });
@@ -0,0 +1,101 @@
1
+ import enums from '../../../../enums.js';
2
+ import { logger } from '../../../../core/util/logger/log-service.js';
3
+ import { inject } from 'dioma';
4
+ import { TvStore } from '../../../dpe/infrastructure/tv.store.js';
5
+
6
+ /**
7
+ * Calcul des déperditions de l’enveloppe GV
8
+ * @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021) chapitre 3
9
+ */
10
+ export class DeperditionService {
11
+ /**
12
+ * @type {TvStore}
13
+ */
14
+ tvStore;
15
+
16
+ /**
17
+ * @param tvStore {TvStore}
18
+ */
19
+ constructor(tvStore = inject(TvStore)) {
20
+ this.tvStore = tvStore;
21
+ }
22
+
23
+ /**
24
+ * Détermination des déperditions pour l'enveloppe concernée
25
+ * @param ctx {Contexte}
26
+ * @param de {DE}
27
+ * @return void
28
+ */
29
+ /* eslint-disable no-unused-vars */
30
+ execute(ctx, de) {
31
+ throw new Error('Unsupported operation');
32
+ }
33
+
34
+ /**
35
+ * Détermination du coefficient de réduction des déperditions b
36
+ * @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021) chapitre 3.1
37
+ *
38
+ * @param d {DeperditionData}
39
+ * @return {number|undefined} Retourne le coefficient de réduction des déperditions b ou undefined si le calcul est impossible
40
+ */
41
+ b(d) {
42
+ let uVue,
43
+ zc,
44
+ rAiuAue = undefined;
45
+ let enumTypeAdjacenceId = d.enumTypeAdjacenceId;
46
+
47
+ if (
48
+ ['8', '9', '11', '12', '13', '14', '15', '16', '17', '18', '19', '21'].includes(
49
+ enumTypeAdjacenceId
50
+ )
51
+ ) {
52
+ if (!d.surfaceAue || d.surfaceAue === 0) {
53
+ return 0;
54
+ }
55
+
56
+ /**
57
+ * @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021)
58
+ * chapitre 3.1 Détermination du coefficient de réduction des déperditions b
59
+ * 'Dans le cas de locaux non chauffés non accessibles (mitoyenneté, espace sans accès…), forfaitairement b = 0,95.'
60
+ */
61
+ if (d.enumCfgIsolationLncId === '1') {
62
+ enumTypeAdjacenceId = undefined;
63
+ } else {
64
+ uVue = this.tvStore.getUVue(enumTypeAdjacenceId) || 0;
65
+ rAiuAue = d.surfaceAiu / d.surfaceAue;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Type d'adjacence 10: 'espace tampon solarisé (véranda,loggia fermée)'
71
+ * Prise en compte de la zone climatique
72
+ */
73
+ if (['10'].includes(enumTypeAdjacenceId)) {
74
+ if (!d.zoneClimatiqueId) {
75
+ logger.warn(
76
+ `impossible de calculer b pour TypeAdjacenceId:${enumTypeAdjacenceId} sans zone climatique`
77
+ );
78
+ return;
79
+ }
80
+ zc = enums.zone_climatique[parseInt(d.zoneClimatiqueId)];
81
+ }
82
+
83
+ return this.tvStore.getB(enumTypeAdjacenceId, uVue, d.enumCfgIsolationLncId, rAiuAue, zc);
84
+ }
85
+
86
+ /**
87
+ * Si Année d'isolation connue alors on prend cette donnée.
88
+ * Sinon
89
+ * Si Année de construction ≤74 alors Année d’isolation = 75-77
90
+ * Sinon Année d’isolation = Année de construction
91
+ *
92
+ * @param enumPeriodeIsolationId {number}
93
+ * @param ctx {Contexte}
94
+ * @return {string} ID de la période d'isolation
95
+ */
96
+ getEnumPeriodeIsolationId(enumPeriodeIsolationId, ctx) {
97
+ return (
98
+ enumPeriodeIsolationId || Math.max(parseInt(ctx.enumPeriodeConstructionId), 3).toString()
99
+ );
100
+ }
101
+ }