@open3cl/engine 1.0.13 → 1.0.15

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 (30) hide show
  1. package/13.2_generateur_combustion_ch.js +1 -1
  2. package/features/dpe/domain/models/climatisation.model.ts +1 -0
  3. package/features/dpe/domain/models/installation-chauffage.model.ts +24 -0
  4. package/features/dpe/domain/models/type-generateur.model.js +8 -0
  5. package/features/dpe/infrastructure/ch/chTv.store.js +94 -0
  6. package/features/dpe/infrastructure/ch/chTv.store.spec.js +99 -0
  7. package/features/dpe/infrastructure/ecs/ecsTv.store.js +5 -3
  8. package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +4 -0
  9. package/features/dpe/infrastructure/froid/frTv.store.js +27 -0
  10. package/features/dpe/infrastructure/froid/frTv.store.spec.js +22 -0
  11. package/features/dpe/infrastructure/tv.store.js +28 -0
  12. package/features/dpe/infrastructure/tv.store.spec.js +12 -0
  13. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +14 -0
  14. package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +14 -0
  15. package/features/engine/domain/ch/emetteur-ch.service.js +100 -0
  16. package/features/engine/domain/ch/emetteur-ch.service.spec.js +78 -0
  17. package/features/engine/domain/ch/generateur-ch.service.js +365 -0
  18. package/features/engine/domain/ch/generateur-ch.service.spec.js +734 -0
  19. package/features/engine/domain/ch/installation-ch.service.js +39 -0
  20. package/features/engine/domain/ch/installation-ch.service.spec.js +41 -0
  21. package/features/engine/domain/conso/conso.service.js +26 -0
  22. package/features/engine/domain/conso/conso.service.spec.js +29 -0
  23. package/features/engine/domain/conso/froid/conso-froid.service.js +94 -0
  24. package/features/engine/domain/conso/froid/conso-froid.service.spec.js +152 -0
  25. package/features/engine/domain/contexte.builder.js +1 -0
  26. package/features/engine/domain/contexte.builder.spec.js +2 -0
  27. package/features/engine/domain/ecs/generateur-ecs.service.js +2 -2
  28. package/features/engine/domain/engine.service.js +10 -0
  29. package/features/engine/domain/models/contexte.model.ts +1 -0
  30. package/package.json +1 -1
@@ -0,0 +1,78 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
2
+ import { ChTvStore } from '../../../dpe/infrastructure/ch/chTv.store.js';
3
+ import { EmetteurChService } from './emetteur-ch.service.js';
4
+
5
+ /** @type {EmetteurChService} **/
6
+ let service;
7
+
8
+ /** @type {ChTvStore} **/
9
+ let chTvStore;
10
+
11
+ describe('Calcul des caractéristiques des générateurs de chauffage', () => {
12
+ beforeEach(() => {
13
+ chTvStore = new ChTvStore();
14
+ service = new EmetteurChService(chTvStore);
15
+ });
16
+
17
+ test("Determination de l'année d'installation des emetteurs", () => {
18
+ /** @type {EmetteurChauffage} **/
19
+ const emetteurChauffage = {
20
+ donnee_entree: {}
21
+ };
22
+
23
+ expect(
24
+ service.periodeInstallationEmetteur({ anneeConstruction: 1850 }, emetteurChauffage)
25
+ ).toBe(1);
26
+ expect(
27
+ service.periodeInstallationEmetteur({ anneeConstruction: 1985 }, emetteurChauffage)
28
+ ).toBe(2);
29
+ expect(
30
+ service.periodeInstallationEmetteur({ anneeConstruction: 2002 }, emetteurChauffage)
31
+ ).toBe(3);
32
+
33
+ emetteurChauffage.donnee_entree.enum_periode_installation_emetteur_id = 3;
34
+
35
+ expect(
36
+ service.periodeInstallationEmetteur({ anneeConstruction: 1850 }, emetteurChauffage)
37
+ ).toBe(3);
38
+ });
39
+
40
+ test('Détermination des températures de fonctionnement à 30 et 100% de charge', () => {
41
+ vi.spyOn(chTvStore, 'temperatureFonctionnement')
42
+ .mockReturnValueOnce(25)
43
+ .mockReturnValueOnce(32)
44
+ .mockReturnValueOnce(27)
45
+ .mockReturnValueOnce(31);
46
+
47
+ vi.spyOn(chTvStore, 'temperatureFonctionnement').mockReturnValue(32);
48
+ /** @type {GenerateurChauffageDE} */
49
+ const generateurChauffageDE = {
50
+ enum_type_generateur_ch_id: 80
51
+ };
52
+
53
+ /** @type {EmetteurChauffage[]} */
54
+ const emetteursChauffage = [
55
+ {
56
+ donnee_entree: { enum_temp_distribution_ch_id: 1 }
57
+ },
58
+ {
59
+ donnee_entree: { enum_temp_distribution_ch_id: 2, enum_periode_installation_emetteur_id: 1 }
60
+ },
61
+ {
62
+ donnee_entree: { enum_temp_distribution_ch_id: 2, enum_periode_installation_emetteur_id: 2 }
63
+ }
64
+ ];
65
+
66
+ expect(
67
+ service.temperatureFonctionnement({}, generateurChauffageDE, emetteursChauffage)
68
+ ).toStrictEqual({
69
+ temp_fonc_30: 27,
70
+ temp_fonc_100: 32
71
+ });
72
+ expect(chTvStore.temperatureFonctionnement).toHaveBeenCalledTimes(4);
73
+ expect(chTvStore.temperatureFonctionnement).toHaveBeenCalledWith('30', 80, 2, 1);
74
+ expect(chTvStore.temperatureFonctionnement).toHaveBeenCalledWith('100', 80, 2, 1);
75
+ expect(chTvStore.temperatureFonctionnement).toHaveBeenCalledWith('30', 80, 2, 2);
76
+ expect(chTvStore.temperatureFonctionnement).toHaveBeenCalledWith('100', 80, 2, 2);
77
+ });
78
+ });
@@ -0,0 +1,365 @@
1
+ import { inject } from 'dioma';
2
+ import { ChTvStore } from '../../../dpe/infrastructure/ch/chTv.store.js';
3
+ import { excel_to_js_exec } from '../../../../utils.js';
4
+ import { TvStore } from '../../../dpe/infrastructure/tv.store.js';
5
+ import { EmetteurChService } from './emetteur-ch.service.js';
6
+ import { TypeGenerateur } from '../../../dpe/domain/models/type-generateur.model.js';
7
+
8
+ /**
9
+ * Calcul des données de calcul pour chacun des générateurs
10
+ * Données calculées
11
+ * — typeGenerateur : pertes à l’arrêt (kW)
12
+ * — qp0 : pertes à l’arrêt (kW)
13
+ * — rpn : rendements à pleine charge
14
+ * — rpint : rendements à charge intermédiaire
15
+ * — pveil : puissance de la veilleuse
16
+ */
17
+ export class GenerateurChService {
18
+ /**
19
+ * @type {ChTvStore}
20
+ */
21
+ #chTvStore;
22
+
23
+ /**
24
+ * @type {TvStore}
25
+ */
26
+ #tvStore;
27
+
28
+ /**
29
+ * @type {EmetteurChService}
30
+ */
31
+ #emetteurChService;
32
+
33
+ /**
34
+ * @param chTvStore {ChTvStore}
35
+ * @param tvStore {TvStore}
36
+ * @param emetteurChService {EmetteurChService}
37
+ */
38
+ constructor(
39
+ chTvStore = inject(ChTvStore),
40
+ tvStore = inject(TvStore),
41
+ emetteurChService = inject(EmetteurChService)
42
+ ) {
43
+ this.#chTvStore = chTvStore;
44
+ this.#tvStore = tvStore;
45
+ this.#emetteurChService = emetteurChService;
46
+ }
47
+
48
+ /**
49
+ * Détermination des données de calcul pour une installation de chauffage
50
+ *
51
+ * @param ctx {Contexte}
52
+ * @param logement {Logement}
53
+ * @param installationChauffage {InstallationChauffage}
54
+ */
55
+ execute(ctx, logement, installationChauffage) {
56
+ const generateursChauffage =
57
+ installationChauffage.generateur_chauffage_collection?.generateur_chauffage || [];
58
+
59
+ generateursChauffage.forEach((generateurChauffage) => {
60
+ /** @type {GenerateurChauffageDE}*/
61
+ const generateurChauffageDE = generateurChauffage.donnee_entree;
62
+
63
+ /** @type {GenerateurChauffageDI}*/
64
+ const generateurChauffageDI = generateurChauffage.donnee_intermediaire;
65
+
66
+ generateurChauffage.donnee_utilisateur = {
67
+ typeGenerateur: this.typeGenerateur(generateurChauffageDE),
68
+ combustion: this.generateurCombustion(generateurChauffageDE),
69
+ pac: this.generateurPAC(generateurChauffageDE),
70
+ ratio_virtualisation: installationChauffage.donnee_entree.ratio_virtualisation || 1
71
+ };
72
+
73
+ if (generateurChauffage.donnee_utilisateur.combustion) {
74
+ // Calcul de la puissance nominale si non définie
75
+ if (!generateurChauffageDI.pn) {
76
+ generateurChauffage.donnee_intermediaire.pn = this.pn(ctx, logement);
77
+ }
78
+
79
+ generateurChauffage.donnee_utilisateur.generateur = this.#chTvStore.getGenerateurCombustion(
80
+ generateurChauffageDE.enum_type_generateur_ch_id,
81
+ generateurChauffage.donnee_intermediaire.pn /
82
+ ((generateurChauffage.donnee_utilisateur.ratio_virtualisation || 1) * 1000)
83
+ );
84
+
85
+ const emetteurs = (
86
+ installationChauffage.emetteur_chauffage_collection?.emetteur_chauffage || []
87
+ ).filter(
88
+ (emetteur) =>
89
+ emetteur.donnee_entree.enum_lien_generateur_emetteur_id ===
90
+ generateurChauffageDE.enum_lien_generateur_emetteur_id
91
+ );
92
+
93
+ const caracteristiques = this.caracteristiques(ctx, generateurChauffage, emetteurs);
94
+ generateurChauffage.donnee_intermediaire.qp0 = caracteristiques.qp0;
95
+ generateurChauffage.donnee_intermediaire.rpn = caracteristiques.rpn;
96
+ generateurChauffage.donnee_intermediaire.rpint = caracteristiques.rpint;
97
+ generateurChauffage.donnee_intermediaire.pveil = caracteristiques.pveil;
98
+
99
+ if (caracteristiques.temp_fonc_30)
100
+ generateurChauffage.donnee_intermediaire.temp_fonc_30 = caracteristiques.temp_fonc_30;
101
+ if (caracteristiques.temp_fonc_100)
102
+ generateurChauffage.donnee_intermediaire.temp_fonc_100 = caracteristiques.temp_fonc_100;
103
+ }
104
+ });
105
+ }
106
+
107
+ /**
108
+ * Type de générateur de chauffage
109
+ *
110
+ * @param generateurChauffageDE {GenerateurChauffageDE}
111
+ * @return {TypeGenerateur}
112
+ */
113
+ typeGenerateur(generateurChauffageDE) {
114
+ const typeGenerateurChauffage = parseInt(generateurChauffageDE.enum_type_generateur_ch_id);
115
+
116
+ // Chaudière Fioul
117
+ if (typeGenerateurChauffage >= 75 && typeGenerateurChauffage <= 84) {
118
+ return TypeGenerateur.CHAUDIERE;
119
+ }
120
+ // Chaudière Gaz
121
+ if (typeGenerateurChauffage >= 85 && typeGenerateurChauffage <= 97) {
122
+ return TypeGenerateur.CHAUDIERE;
123
+ }
124
+ // Chaudière gpl
125
+ if (typeGenerateurChauffage >= 127 && typeGenerateurChauffage <= 139) {
126
+ return TypeGenerateur.CHAUDIERE;
127
+ }
128
+ // Chaudière hybride
129
+ if ([148, 149, 150, 151, 160, 161].includes(typeGenerateurChauffage)) {
130
+ return TypeGenerateur.CHAUDIERE;
131
+ }
132
+
133
+ return TypeGenerateur.OTHER;
134
+ }
135
+
136
+ /**
137
+ * Return true si le générateur de chauffage est à combustion
138
+ *
139
+ * @param generateurChauffageDE {GenerateurChauffageDE}
140
+ * @return {boolean}
141
+ */
142
+ generateurCombustion(generateurChauffageDE) {
143
+ return this.#chTvStore
144
+ .getCombustionGenerateurs()
145
+ .includes(parseInt(generateurChauffageDE.enum_type_generateur_ch_id));
146
+ }
147
+
148
+ /**
149
+ * Return true si le générateur de chauffage est une PAC
150
+ *
151
+ * @param generateurChauffageDE {GenerateurChauffageDE}
152
+ * @return {boolean}
153
+ */
154
+ generateurPAC(generateurChauffageDE) {
155
+ return this.#chTvStore
156
+ .getPacGenerateurs()
157
+ .includes(parseInt(generateurChauffageDE.enum_type_generateur_ch_id));
158
+ }
159
+
160
+ /**
161
+ * Calcul des caractéristiques du générateur de chauffage
162
+ *
163
+ * Données calculées
164
+ * — qp0 : pertes à l’arrêt (kW)
165
+ * — rpn : rendements à pleine charge
166
+ * — rpint : rendements à charge intermédiaire
167
+ * — pveil : puissance de la veilleuse
168
+ * — temp_fonc_30 : températeur de fonctionnement du générateur à 30% de charge
169
+ * — temp_fonc_100 : températeur de fonctionnement du générateur à 100% de charge
170
+ *
171
+ * @param ctx {Contexte}
172
+ * @param generateurChauffage {GenerateurChauffage}
173
+ * @param emetteursChauffage {EmetteurChauffage[]}
174
+ * @return {{qp0: number, rpn: number, rpint: number, rpint: number, pveil: number, temp_fonc_30: number, temp_fonc_100: number}}
175
+ */
176
+ caracteristiques(ctx, generateurChauffage, emetteursChauffage) {
177
+ const caracteristiques = {
178
+ qp0: this.qp0(generateurChauffage),
179
+ ...this.rpnrpint(generateurChauffage),
180
+ pveil: this.pveil(generateurChauffage)
181
+ };
182
+
183
+ if (generateurChauffage.donnee_utilisateur.typeGenerateur === TypeGenerateur.CHAUDIERE) {
184
+ const { temp_fonc_30, temp_fonc_100 } = this.temperatureFonctionnement(
185
+ ctx,
186
+ generateurChauffage,
187
+ emetteursChauffage
188
+ );
189
+
190
+ if (temp_fonc_30) caracteristiques.temp_fonc_30 = temp_fonc_30;
191
+ if (temp_fonc_100) caracteristiques.temp_fonc_100 = temp_fonc_100;
192
+ }
193
+
194
+ return caracteristiques;
195
+ }
196
+
197
+ /**
198
+ * Calcul de la puissance nominale du générateur
199
+ *
200
+ * @param ctx {Contexte}
201
+ * @param logement {Logement}
202
+ * @return {number}
203
+ */
204
+ pn(ctx, logement) {
205
+ const Tbase = this.#tvStore.getTempBase(ctx.altitude.id, ctx.zoneClimatique.id);
206
+ return (1.2 * logement.sortie.deperdition.deperdition_enveloppe * (19 - Tbase)) / 0.95 ** 3;
207
+ }
208
+
209
+ /**
210
+ * Calcul des pertes à l'arrêt qp0 du générateur
211
+ *
212
+ * @param generateurChauffage {GenerateurChauffage}
213
+ * @return {number}
214
+ */
215
+ qp0(generateurChauffage) {
216
+ const generateurChauffageDE = generateurChauffage.donnee_entree;
217
+ const generateurChauffageDU = generateurChauffage.donnee_utilisateur;
218
+ const generateurChauffageDI = generateurChauffage.donnee_intermediaire;
219
+
220
+ const E_tab = {
221
+ 0: 2.5,
222
+ 1: 1.75
223
+ };
224
+
225
+ const F_tab = {
226
+ 0: -0.8,
227
+ 1: -0.55
228
+ };
229
+
230
+ const E = E_tab[generateurChauffageDE.presence_ventouse];
231
+ const F = F_tab[generateurChauffageDE.presence_ventouse];
232
+
233
+ /**
234
+ * 4 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0, autres données forfaitaires
235
+ * 5 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0,temp_fonc_30,temp_fonc_100
236
+ */
237
+ if ([4, 5].includes(parseInt(generateurChauffageDE.enum_methode_saisie_carac_sys_id))) {
238
+ return generateurChauffageDI.qp0;
239
+ } else {
240
+ const qp0_perc = generateurChauffageDU.generateur?.qp0_perc;
241
+
242
+ if (qp0_perc) {
243
+ const qp0_calc = excel_to_js_exec(
244
+ qp0_perc,
245
+ generateurChauffageDI.pn / generateurChauffageDU.ratio_virtualisation,
246
+ E,
247
+ F
248
+ );
249
+
250
+ // Certaines chaudières ont un qp0 en % de pn, d'autres ont des valeurs constantes
251
+ return qp0_perc.includes('Pn')
252
+ ? qp0_calc * 1000 * generateurChauffageDU.ratio_virtualisation
253
+ : qp0_perc.includes('%')
254
+ ? qp0_calc * generateurChauffageDI.pn
255
+ : qp0_calc * 1000;
256
+ }
257
+ }
258
+
259
+ return 0;
260
+ }
261
+
262
+ /**
263
+ * Calcul de la puissance de la veilleuse du générateur
264
+ *
265
+ * @param generateurChauffage {GenerateurChauffage}
266
+ * @return {number}
267
+ */
268
+ pveil(generateurChauffage) {
269
+ const generateurChauffageDE = generateurChauffage.donnee_entree;
270
+ const generateurChauffageDI = generateurChauffage.donnee_intermediaire;
271
+
272
+ /**
273
+ * 1 - valeurs forfaitaires
274
+ */
275
+ if (
276
+ parseInt(generateurChauffageDE.enum_methode_saisie_carac_sys_id) === 1 ||
277
+ !generateurChauffageDI.pveilleuse
278
+ ) {
279
+ return generateurChauffage.donnee_utilisateur.generateur?.pveil || 0;
280
+ } else {
281
+ return generateurChauffageDI.pveilleuse;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Calcul des températures de fonctionnement du générateur à 30% et 100% de charge
287
+ *
288
+ * @param ctx {Contexte}
289
+ * @param generateurChauffage {GenerateurChauffage}
290
+ * @param emetteursChauffage {EmetteurChauffage[]}
291
+ * @return {{temp_fonc_30: number, temp_fonc_100: number}}
292
+ */
293
+ temperatureFonctionnement(ctx, generateurChauffage, emetteursChauffage) {
294
+ const generateurChauffageDE = generateurChauffage.donnee_entree;
295
+ const generateurChauffageDI = generateurChauffage.donnee_intermediaire;
296
+
297
+ /**
298
+ * 5 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0,temp_fonc_30,temp_fonc_100
299
+ */
300
+ if (
301
+ parseInt(generateurChauffageDE.enum_methode_saisie_carac_sys_id) === 5 &&
302
+ generateurChauffageDI.temp_fonc_30 &&
303
+ generateurChauffageDI.temp_fonc_100
304
+ ) {
305
+ return {
306
+ temp_fonc_30: generateurChauffageDI.temp_fonc_30,
307
+ temp_fonc_100: generateurChauffageDI.temp_fonc_100
308
+ };
309
+ } else {
310
+ return this.#emetteurChService.temperatureFonctionnement(
311
+ ctx,
312
+ generateurChauffage.donnee_entree,
313
+ emetteursChauffage
314
+ );
315
+ }
316
+ }
317
+
318
+ /**
319
+ * Calcul des rendements à pleine charge et à charge intermédiaire
320
+ *
321
+ * @param generateurChauffage {GenerateurChauffage}
322
+ * @return {{rpn: number, rpint: number}}
323
+ */
324
+ rpnrpint(generateurChauffage) {
325
+ const generateurChauffageDE = generateurChauffage.donnee_entree;
326
+ const generateurChauffageDU = generateurChauffage.donnee_utilisateur;
327
+ const generateurChauffageDI = generateurChauffage.donnee_intermediaire;
328
+
329
+ /**
330
+ * 3 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint, autres données forfaitaires
331
+ * 4 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0, autres données forfaitaires
332
+ * 5 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0,temp_fonc_30,temp_fonc_100
333
+ */
334
+ if ([3, 4, 5].includes(parseInt(generateurChauffageDE.enum_methode_saisie_carac_sys_id))) {
335
+ return {
336
+ rpn: generateurChauffage.donnee_intermediaire.rpn,
337
+ rpint: generateurChauffage.donnee_intermediaire.rpint
338
+ };
339
+ } else {
340
+ const generateurRpn = generateurChauffageDU.generateur?.rpn;
341
+ const generateurRpint = generateurChauffageDU.generateur?.rpint;
342
+
343
+ let rpn = 0;
344
+ let rpint = 0;
345
+
346
+ if (generateurRpn) {
347
+ rpn =
348
+ excel_to_js_exec(
349
+ generateurRpn,
350
+ generateurChauffageDI.pn / generateurChauffageDU.ratio_virtualisation
351
+ ) / 100;
352
+ }
353
+
354
+ if (generateurRpint) {
355
+ rpint =
356
+ excel_to_js_exec(
357
+ generateurRpint,
358
+ generateurChauffageDI.pn / generateurChauffageDU.ratio_virtualisation
359
+ ) / 100;
360
+ }
361
+
362
+ return { rpn, rpint };
363
+ }
364
+ }
365
+ }