@open3cl/engine 1.0.9 → 1.0.11
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/features/dpe/domain/models/type-habitation.model.js +8 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.js +22 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +33 -0
- package/features/dpe/infrastructure/{baieVitreeTv.store.js → enveloppe/baieVitreeTv.store.js} +74 -4
- package/features/dpe/infrastructure/{baieVitreeTv.store.spec.js → enveloppe/baieVitreeTv.store.spec.js} +106 -0
- package/features/dpe/infrastructure/{pontThermiqueTv.store.js → enveloppe/pontThermiqueTv.store.js} +3 -3
- package/features/dpe/infrastructure/froid/frTv.store.js +36 -0
- package/features/dpe/infrastructure/froid/frTv.store.spec.js +52 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +74 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +85 -0
- package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.js +134 -0
- package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.spec.js +167 -0
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.js +58 -0
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +67 -0
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.js +131 -0
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +229 -0
- package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.js +168 -0
- package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.spec.js +230 -0
- package/features/engine/domain/contexte.builder.js +103 -64
- package/features/engine/domain/contexte.builder.spec.js +99 -64
- package/features/engine/domain/engine.service.js +16 -2
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.js +2 -2
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +1 -1
- package/features/engine/domain/enveloppe/deperdition-enveloppe.service.js +19 -0
- package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +3 -3
- package/features/engine/domain/enveloppe/deperdition.service.js +2 -3
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.js +44 -0
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +81 -0
- package/features/engine/domain/enveloppe/mur/deperdition-mur.service.js +3 -3
- package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +30 -10
- package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.js +2 -2
- package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +18 -6
- package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.js +2 -2
- package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +21 -7
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.js +1 -1
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +1 -1
- package/features/engine/domain/enveloppe/porte/deperdition-porte.service.js +1 -1
- package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +2 -2
- package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.js +1 -1
- package/features/engine/domain/logement/nadeq.service.js +63 -0
- package/features/engine/domain/logement/nadeq.service.spec.js +61 -0
- package/features/engine/domain/models/contexte.model.ts +19 -5
- package/features/engine/domain/models/deperdition.model.ts +1 -1
- package/package.json +1 -1
- /package/features/dpe/infrastructure/{pontThermiqueTv.store.spec.js → enveloppe/pontThermiqueTv.store.spec.js} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { tvs as tv } from '../../../../tv-v2.js';
|
|
2
|
+
import { TvStore } from './../tv.store.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Accès aux données des tables de valeurs pour le besoin en eau chaude sanitaire
|
|
6
|
+
*/
|
|
7
|
+
export class EcsTvStore extends TvStore {
|
|
8
|
+
/**
|
|
9
|
+
* Température moyenne d’eau froide sanitaire sur le mois j (°C).
|
|
10
|
+
* La température d’eau froide est une donnée climatique mensuelle pour chacune des 8 zones climatiques
|
|
11
|
+
* @see 11.1 Calcul du besoin d’ECS : Tefs
|
|
12
|
+
*
|
|
13
|
+
* @param classeAltitude {string}
|
|
14
|
+
* @param zoneClimatique {string}
|
|
15
|
+
* @param mois {string}
|
|
16
|
+
*
|
|
17
|
+
* @return {number|undefined}
|
|
18
|
+
*/
|
|
19
|
+
getTefs(classeAltitude, zoneClimatique, mois) {
|
|
20
|
+
return tv['tefs'][classeAltitude][mois][zoneClimatique];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
2
|
+
import { EcsTvStore } from './ecsTv.store.js';
|
|
3
|
+
|
|
4
|
+
/** @type {EcsTvStore} **/
|
|
5
|
+
let ecsTvStore;
|
|
6
|
+
|
|
7
|
+
describe('Lecture des tables de valeurs', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
ecsTvStore = new EcsTvStore();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('Lecture des valeurs de tefs', () => {
|
|
13
|
+
test.each([
|
|
14
|
+
{
|
|
15
|
+
label: 'température moyenne eau froide sanitaire en janvier sur zone h1a inférieure à 400m',
|
|
16
|
+
classeAltitude: 'inférieur à 400m',
|
|
17
|
+
zoneClimatique: 'h1a',
|
|
18
|
+
mois: 'Janvier',
|
|
19
|
+
expected: 7.8
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label:
|
|
23
|
+
'température moyenne eau froide sanitaire en Décembre sur zone h3 inférieure entre 400-800m',
|
|
24
|
+
classeAltitude: '400-800m',
|
|
25
|
+
zoneClimatique: 'h3',
|
|
26
|
+
mois: 'Décembre',
|
|
27
|
+
expected: 10.1
|
|
28
|
+
}
|
|
29
|
+
])(`$label`, ({ classeAltitude, zoneClimatique, mois, expected }) => {
|
|
30
|
+
expect(ecsTvStore.getTefs(classeAltitude, zoneClimatique, mois)).toBe(expected);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
package/features/dpe/infrastructure/{baieVitreeTv.store.js → enveloppe/baieVitreeTv.store.js}
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { tvs as tv } from '
|
|
2
|
-
import { getRange } from '
|
|
3
|
-
import { logger } from '
|
|
4
|
-
import { TvStore } from '
|
|
1
|
+
import { tvs as tv } from '../../../../tv-v2.js';
|
|
2
|
+
import { getRange } from '../../../../utils.js';
|
|
3
|
+
import { logger } from '../../../../core/util/logger/log-service.js';
|
|
4
|
+
import { TvStore } from './../tv.store.js';
|
|
5
|
+
import enums from '../../../../enums.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Accès aux données des tables de valeurs pour les baies vitrées
|
|
@@ -289,4 +290,73 @@ export class BaieVitreeTvStore extends TvStore {
|
|
|
289
290
|
|
|
290
291
|
return parseFloat(fe2);
|
|
291
292
|
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Calcul des coefficients de réduction de température des espaces tampons
|
|
296
|
+
*
|
|
297
|
+
* @param zoneClimatique {string}
|
|
298
|
+
* @param enumCfgIsolationLncId {number}
|
|
299
|
+
* @return {number|undefined}
|
|
300
|
+
*/
|
|
301
|
+
getBver(zoneClimatique, enumCfgIsolationLncId) {
|
|
302
|
+
const bver = tv['coef_reduction_deperdition'].find(
|
|
303
|
+
(v) =>
|
|
304
|
+
zoneClimatique.toLowerCase().startsWith(v.zone_climatique?.toLowerCase()) &&
|
|
305
|
+
parseInt(v.enum_cfg_isolation_lnc_id) === parseInt(enumCfgIsolationLncId)
|
|
306
|
+
)?.b;
|
|
307
|
+
|
|
308
|
+
if (!bver) {
|
|
309
|
+
logger.error(
|
|
310
|
+
`Pas de valeur b pour zoneClimatique:${zoneClimatique}, enumCfgIsolationLncId:${enumCfgIsolationLncId}`
|
|
311
|
+
);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return parseFloat(bver);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Calcul des coefficients de transparence des espaces tampons
|
|
320
|
+
*
|
|
321
|
+
* @param tvCoefTransparenceEtsId {number}
|
|
322
|
+
* @return {number|undefined}
|
|
323
|
+
*/
|
|
324
|
+
getCoefTransparenceEts(tvCoefTransparenceEtsId) {
|
|
325
|
+
const coefTransparence = tv['coef_transparence_ets'].find(
|
|
326
|
+
(v) => parseInt(v.tv_coef_transparence_ets_id) === parseInt(tvCoefTransparenceEtsId)
|
|
327
|
+
)?.coef_transparence_ets;
|
|
328
|
+
|
|
329
|
+
if (!coefTransparence) {
|
|
330
|
+
logger.error(
|
|
331
|
+
`Pas de valeur coef_transparence_ets pour tvCoefTransparenceEtsId:${tvCoefTransparenceEtsId}`
|
|
332
|
+
);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return parseFloat(coefTransparence);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @see 18.5 - Coefficients d’orientation et d’inclinaison des parois vitrées : C1
|
|
341
|
+
*
|
|
342
|
+
* @param enumOrientationId {number}
|
|
343
|
+
* @param enumInclinaisonVitrageId {number}
|
|
344
|
+
* @param zoneClimatiqueId {number}
|
|
345
|
+
* @param mois {string}
|
|
346
|
+
*
|
|
347
|
+
* @return {number|undefined}
|
|
348
|
+
*/
|
|
349
|
+
getCoefficientBaieVitree(enumOrientationId, enumInclinaisonVitrageId, zoneClimatiqueId, mois) {
|
|
350
|
+
const orientation = enums.orientation[enumOrientationId];
|
|
351
|
+
const inclinaison = enums.inclinaison_vitrage[enumInclinaisonVitrageId];
|
|
352
|
+
const zoneClimatique = enums.zone_climatique[zoneClimatiqueId];
|
|
353
|
+
|
|
354
|
+
const c1ZoneClimatique = tv['c1'][zoneClimatique][mois];
|
|
355
|
+
|
|
356
|
+
if (inclinaison === 'horizontal') {
|
|
357
|
+
return c1ZoneClimatique[inclinaison];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return c1ZoneClimatique[`${orientation} ${inclinaison}`];
|
|
361
|
+
}
|
|
292
362
|
}
|
|
@@ -345,6 +345,112 @@ describe('Lecture des tables de valeurs', () => {
|
|
|
345
345
|
});
|
|
346
346
|
});
|
|
347
347
|
|
|
348
|
+
describe('lecture des valeurs coefficients de réduction de température des espaces tampons', () => {
|
|
349
|
+
test.each([
|
|
350
|
+
{
|
|
351
|
+
label: 'lc non isolé + espace tampon solarisé orienté nord',
|
|
352
|
+
zoneClimatique: 'H1a',
|
|
353
|
+
enumCfgIsolationLncId: '9',
|
|
354
|
+
expected: 0.85
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
label: 'lc isolé + espace tampon solarisé orienté sud',
|
|
358
|
+
zoneClimatique: 'H2C',
|
|
359
|
+
enumCfgIsolationLncId: '7',
|
|
360
|
+
expected: 0.57
|
|
361
|
+
}
|
|
362
|
+
])(
|
|
363
|
+
`incidence masque proche pour baie vitrée $label`,
|
|
364
|
+
({ zoneClimatique, enumCfgIsolationLncId, expected }) => {
|
|
365
|
+
expect(tvStore.getBver(zoneClimatique, enumCfgIsolationLncId)).toBe(expected);
|
|
366
|
+
}
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
test('pas de valeur de coefficients de réduction de température', () => {
|
|
370
|
+
const ug = tvStore.getBver('h3C', 1);
|
|
371
|
+
expect(ug).toBeUndefined();
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
describe('lecture des valeurs de coefficients de transparence des espaces tampons', () => {
|
|
376
|
+
test.each([
|
|
377
|
+
{
|
|
378
|
+
label: 'Parois en polycarbonate',
|
|
379
|
+
tvCoefTransparenceEtsId: '9',
|
|
380
|
+
expected: 0.39
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
label: 'Parois triple vitrage en Bois / Bois-métal',
|
|
384
|
+
tvCoefTransparenceEtsId: '5',
|
|
385
|
+
expected: 0.49
|
|
386
|
+
}
|
|
387
|
+
])(
|
|
388
|
+
`incidence masque proche pour baie vitrée $label`,
|
|
389
|
+
({ tvCoefTransparenceEtsId, expected }) => {
|
|
390
|
+
expect(tvStore.getCoefTransparenceEts(tvCoefTransparenceEtsId)).toBe(expected);
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
test('pas de valeur de coefficients de transparence', () => {
|
|
395
|
+
const ug = tvStore.getCoefTransparenceEts(0);
|
|
396
|
+
expect(ug).toBeUndefined();
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
describe("lecture des coefficients d'orientation et inclinaison des parois vitrées", () => {
|
|
401
|
+
test.each([
|
|
402
|
+
{
|
|
403
|
+
label: 'Baie vitrée orientée nord, inclinaison inf25°',
|
|
404
|
+
enumOrientationId: '2',
|
|
405
|
+
enumInclinaisonVitrageId: '1',
|
|
406
|
+
zoneClimatiqueId: '1',
|
|
407
|
+
mois: 'Janvier',
|
|
408
|
+
expected: 0.52
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
label: 'Baie vitrée orientée nord, inclinaison inf25°',
|
|
412
|
+
enumOrientationId: '2',
|
|
413
|
+
enumInclinaisonVitrageId: '1',
|
|
414
|
+
zoneClimatiqueId: '1',
|
|
415
|
+
mois: 'Juillet',
|
|
416
|
+
expected: 1.98
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
label: 'Baie vitrée orientée sud, inclinaison sup75°',
|
|
420
|
+
enumOrientationId: '1',
|
|
421
|
+
enumInclinaisonVitrageId: '3',
|
|
422
|
+
zoneClimatiqueId: '2',
|
|
423
|
+
mois: 'Janvier',
|
|
424
|
+
expected: 1
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
label: 'Baie vitrée orientée sud, inclinaison horizontale',
|
|
428
|
+
enumOrientationId: '1',
|
|
429
|
+
enumInclinaisonVitrageId: '4',
|
|
430
|
+
zoneClimatiqueId: '2',
|
|
431
|
+
mois: 'Janvier',
|
|
432
|
+
expected: 0.58
|
|
433
|
+
}
|
|
434
|
+
])(
|
|
435
|
+
`coefficient pour $label`,
|
|
436
|
+
({ enumOrientationId, enumInclinaisonVitrageId, zoneClimatiqueId, mois, expected }) => {
|
|
437
|
+
expect(
|
|
438
|
+
tvStore.getCoefficientBaieVitree(
|
|
439
|
+
enumOrientationId,
|
|
440
|
+
enumInclinaisonVitrageId,
|
|
441
|
+
zoneClimatiqueId,
|
|
442
|
+
mois
|
|
443
|
+
)
|
|
444
|
+
).toMatchObject(expected);
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test('lecture des épaisseurs disponibles pour les coefficients de transmission thermique ug', () => {
|
|
450
|
+
const ug = tvStore.getEpaisseurAvailableForUg();
|
|
451
|
+
expect(ug).toStrictEqual([0, 6, 8, 10, 12, 14, 15, 16, 18, 20]);
|
|
452
|
+
});
|
|
453
|
+
|
|
348
454
|
test('lecture des épaisseurs disponibles pour les coefficients de transmission thermique ug', () => {
|
|
349
455
|
const ug = tvStore.getEpaisseurAvailableForUg();
|
|
350
456
|
expect(ug).toStrictEqual([0, 6, 8, 10, 12, 14, 15, 16, 18, 20]);
|
package/features/dpe/infrastructure/{pontThermiqueTv.store.js → enveloppe/pontThermiqueTv.store.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { tvs as tv } from '
|
|
2
|
-
import { logger } from '
|
|
3
|
-
import { TvStore } from '
|
|
1
|
+
import { tvs as tv } from '../../../../tv-v2.js';
|
|
2
|
+
import { logger } from '../../../../core/util/logger/log-service.js';
|
|
3
|
+
import { TvStore } from './../tv.store.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Accès aux données des tables de valeurs pour les baies vitrées
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { tvs as tv } from '../../../../tv-v2.js';
|
|
2
|
+
import { TvStore } from './../tv.store.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Accès aux données des tables de valeurs pour le besoin en froid
|
|
6
|
+
*/
|
|
7
|
+
export class FrTvStore extends TvStore {
|
|
8
|
+
/**
|
|
9
|
+
* Recherche des valeurs nécessaires au calcul du besoin en froid
|
|
10
|
+
* @see 10.2 Calcul du besoin mensuel de froid
|
|
11
|
+
* — e : nombre d’heures de chauffage pour un mois donné et une consigne de refroidissement à 26°C (comportement dépensier).
|
|
12
|
+
* — nref26 : nombre d’heures de chauffage pour un mois donné et une consigne de refroidissement à 26°C (comportement dépensier).
|
|
13
|
+
* — nref28 : nombre d’heures de chauffage pour un mois donné et une consigne de refroidissement à 28°C (comportement conventionnel).
|
|
14
|
+
* — e_fr_26 : ensoleillement reçu en période de refroidissement pour un mois donné et une consigne de refroidissement à 26°C (comportement conventionnel).
|
|
15
|
+
* — e_fr_28 : ensoleillement reçu en période de refroidissement pour un mois donné et une consigne de refroidissement à 28°C (comportement conventionnel).
|
|
16
|
+
* — textmoy_clim_26 : Température extérieure moyenne pour un mois donné et une consigne de refroidissement à 26°C (comportement conventionnel).
|
|
17
|
+
* — textmoy_clim_28 : nombre d’heures de chauffage pour un mois donné et une consigne de refroidissement à 28°C (comportement conventionnel).
|
|
18
|
+
*
|
|
19
|
+
* @param type {'e', nref26' | 'nref28' | 'e_fr_26' | 'e_fr_28' | 'textmoy_clim_26' | 'textmoy_clim_28'}
|
|
20
|
+
* @param classeAltitude {string}
|
|
21
|
+
* @param zoneClimatique {string}
|
|
22
|
+
* @param mois {string}
|
|
23
|
+
* @param ilpa {number|undefined} 1 si bien à inertie lourde, 0 sinon
|
|
24
|
+
*
|
|
25
|
+
* @return {number|undefined}
|
|
26
|
+
*/
|
|
27
|
+
getData(type, classeAltitude, zoneClimatique, mois, ilpa = undefined) {
|
|
28
|
+
let values = tv[type];
|
|
29
|
+
|
|
30
|
+
if (ilpa !== undefined) {
|
|
31
|
+
values = values[ilpa];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return values[classeAltitude][mois][zoneClimatique];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from 'vitest';
|
|
2
|
+
import { FrTvStore } from './frTv.store.js';
|
|
3
|
+
|
|
4
|
+
/** @type {FrTvStore} **/
|
|
5
|
+
let tvStore;
|
|
6
|
+
|
|
7
|
+
describe('Lecture des tables de valeurs', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
tvStore = new FrTvStore();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('lecture des valeurs par zone climatique et altitude', () => {
|
|
13
|
+
test.each([
|
|
14
|
+
{
|
|
15
|
+
type: 'e',
|
|
16
|
+
ilpa: 1,
|
|
17
|
+
expected: 60.45
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
type: 'e',
|
|
21
|
+
ilpa: 0,
|
|
22
|
+
expected: 84.66
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
type: 'nref26',
|
|
26
|
+
expected: 5.98
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'nref28',
|
|
30
|
+
expected: 1.14
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'e_fr_26',
|
|
34
|
+
expected: 5.98
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'e_fr_28',
|
|
38
|
+
expected: 1.14
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: 'textmoy_clim_26',
|
|
42
|
+
expected: 28.4
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
type: 'textmoy_clim_28',
|
|
46
|
+
expected: 28.4
|
|
47
|
+
}
|
|
48
|
+
])(`type: $type, ilpa: $ilpa`, ({ type, ilpa = undefined, expected }) => {
|
|
49
|
+
expect(tvStore.getData(type, '400-800m', 'h1a', 'Juin', ilpa)).toBe(expected);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { inject } from 'dioma';
|
|
2
|
+
import { BesoinEcsService } from './ecs/besoin-ecs.service.js';
|
|
3
|
+
import { SurfaceSudEquivalenteService } from './surface-sud-equivalente.service.js';
|
|
4
|
+
import { BesoinFroidService } from './froid/besoin-froid.service.js';
|
|
5
|
+
import { ApportGratuitService } from './apport_gratuit/apport-gratuit.service.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calcul des déperditions de l’enveloppe GV
|
|
9
|
+
* @see Méthode de calcul 3CL-DPE 2021 (cotobre 2021) chapitre 3
|
|
10
|
+
*/
|
|
11
|
+
export class ApportEtBesoinService {
|
|
12
|
+
/**
|
|
13
|
+
* @type {SurfaceSudEquivalenteService}
|
|
14
|
+
*/
|
|
15
|
+
#surfaceSudEquivalenteService;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @type {BesoinEcsService}
|
|
19
|
+
*/
|
|
20
|
+
#besoinEcsService;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @type {BesoinFroidService}
|
|
24
|
+
*/
|
|
25
|
+
#besoinFroidService;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @type {ApportGratuitService}
|
|
29
|
+
*/
|
|
30
|
+
#apportGratuitService;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param besoinEcsService {BesoinEcsService}
|
|
34
|
+
* @param besoinFroidService {BesoinFroidService}
|
|
35
|
+
* @param surfaceSudEquivalenteService {SurfaceSudEquivalenteService}
|
|
36
|
+
* @param apportGratuitService {ApportGratuitService}
|
|
37
|
+
*/
|
|
38
|
+
constructor(
|
|
39
|
+
besoinEcsService = inject(BesoinEcsService),
|
|
40
|
+
besoinFroidService = inject(BesoinFroidService),
|
|
41
|
+
surfaceSudEquivalenteService = inject(SurfaceSudEquivalenteService),
|
|
42
|
+
apportGratuitService = inject(ApportGratuitService)
|
|
43
|
+
) {
|
|
44
|
+
this.#besoinEcsService = besoinEcsService;
|
|
45
|
+
this.#besoinFroidService = besoinFroidService;
|
|
46
|
+
this.#surfaceSudEquivalenteService = surfaceSudEquivalenteService;
|
|
47
|
+
this.#apportGratuitService = apportGratuitService;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Détermination des apports et besoins pour le bien concerné
|
|
52
|
+
*
|
|
53
|
+
* @param ctx {Contexte}
|
|
54
|
+
* @param logement {Logement}
|
|
55
|
+
* @return {ApportEtBesoin}
|
|
56
|
+
*/
|
|
57
|
+
execute(ctx, logement) {
|
|
58
|
+
return {
|
|
59
|
+
...this.#besoinEcsService.execute(ctx),
|
|
60
|
+
...{
|
|
61
|
+
surface_sud_equivalente: this.#surfaceSudEquivalenteService.execute(
|
|
62
|
+
ctx,
|
|
63
|
+
logement.enveloppe
|
|
64
|
+
),
|
|
65
|
+
nadeq: ctx.nadeq,
|
|
66
|
+
v40_ecs_journalier: ctx.nadeq * 56,
|
|
67
|
+
v40_ecs_journalier_depensier: ctx.nadeq * 79
|
|
68
|
+
},
|
|
69
|
+
...this.#besoinFroidService.execute(ctx, logement),
|
|
70
|
+
...this.#apportGratuitService.apportInterne(ctx, logement),
|
|
71
|
+
...this.#apportGratuitService.apportSolaire(ctx, logement)
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
import { SurfaceSudEquivalenteService } from './surface-sud-equivalente.service.js';
|
|
3
|
+
import { BaieVitreeTvStore } from '../../../dpe/infrastructure/enveloppe/baieVitreeTv.store.js';
|
|
4
|
+
import { ApportEtBesoinService } from './apport-et-besoin.service.js';
|
|
5
|
+
import { BesoinEcsService } from './ecs/besoin-ecs.service.js';
|
|
6
|
+
import { BesoinFroidService } from './froid/besoin-froid.service.js';
|
|
7
|
+
import { ApportGratuitService } from './apport_gratuit/apport-gratuit.service.js';
|
|
8
|
+
|
|
9
|
+
/** @type {SurfaceSudEquivalenteService} **/
|
|
10
|
+
let surfaceSudEquivalenteService;
|
|
11
|
+
|
|
12
|
+
/** @type {BesoinEcsService} **/
|
|
13
|
+
let besoinEcsService;
|
|
14
|
+
|
|
15
|
+
/** @type {BesoinFroidService} **/
|
|
16
|
+
let besoinFroidService;
|
|
17
|
+
|
|
18
|
+
/** @type {ApportGratuitService} **/
|
|
19
|
+
let apportGratuitService;
|
|
20
|
+
|
|
21
|
+
/** @type {ApportEtBesoinService} **/
|
|
22
|
+
let service;
|
|
23
|
+
|
|
24
|
+
/** @type {BaieVitreeTvStore} **/
|
|
25
|
+
let tvStore;
|
|
26
|
+
|
|
27
|
+
describe('Calcul des apports et besoin du logement', () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
tvStore = new BaieVitreeTvStore();
|
|
30
|
+
surfaceSudEquivalenteService = new SurfaceSudEquivalenteService(tvStore);
|
|
31
|
+
besoinEcsService = new BesoinEcsService();
|
|
32
|
+
besoinFroidService = new BesoinFroidService();
|
|
33
|
+
apportGratuitService = new ApportGratuitService();
|
|
34
|
+
service = new ApportEtBesoinService(
|
|
35
|
+
besoinEcsService,
|
|
36
|
+
besoinFroidService,
|
|
37
|
+
surfaceSudEquivalenteService,
|
|
38
|
+
apportGratuitService
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('Determination des apports et besoin du logement', () => {
|
|
43
|
+
vi.spyOn(surfaceSudEquivalenteService, 'execute').mockReturnValue(18.5);
|
|
44
|
+
vi.spyOn(besoinEcsService, 'execute').mockReturnValue({
|
|
45
|
+
besoin_ecs: 1526,
|
|
46
|
+
besoin_ecs_depensier: 2685.3
|
|
47
|
+
});
|
|
48
|
+
vi.spyOn(besoinFroidService, 'execute').mockReturnValue({
|
|
49
|
+
besoin_fr: 896,
|
|
50
|
+
besoin_fr_depensier: 1025.3
|
|
51
|
+
});
|
|
52
|
+
vi.spyOn(apportGratuitService, 'apportSolaire').mockReturnValue({
|
|
53
|
+
apport_solaire_ch: 5236.9,
|
|
54
|
+
apport_solaire_fr: 145.2
|
|
55
|
+
});
|
|
56
|
+
vi.spyOn(apportGratuitService, 'apportInterne').mockReturnValue({
|
|
57
|
+
apport_interne_ch: 1236.9,
|
|
58
|
+
apport_interne_fr: 3345.2
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** @type {Contexte} */
|
|
62
|
+
const ctx = { zoneClimatique: { id: 1 }, nadeq: 2.5 };
|
|
63
|
+
/** @type { Logement } **/
|
|
64
|
+
const logement = { enveloppe: {} };
|
|
65
|
+
expect(service.execute(ctx, logement)).toStrictEqual({
|
|
66
|
+
surface_sud_equivalente: 18.5,
|
|
67
|
+
besoin_ecs: 1526,
|
|
68
|
+
besoin_ecs_depensier: 2685.3,
|
|
69
|
+
besoin_fr: 896,
|
|
70
|
+
besoin_fr_depensier: 1025.3,
|
|
71
|
+
apport_solaire_ch: 5236.9,
|
|
72
|
+
apport_solaire_fr: 145.2,
|
|
73
|
+
apport_interne_ch: 1236.9,
|
|
74
|
+
apport_interne_fr: 3345.2,
|
|
75
|
+
nadeq: 2.5,
|
|
76
|
+
v40_ecs_journalier: 140,
|
|
77
|
+
v40_ecs_journalier_depensier: 197.5
|
|
78
|
+
});
|
|
79
|
+
expect(surfaceSudEquivalenteService.execute).toHaveBeenCalledWith(ctx, logement.enveloppe);
|
|
80
|
+
expect(besoinEcsService.execute).toHaveBeenCalledWith(ctx);
|
|
81
|
+
expect(besoinFroidService.execute).toHaveBeenCalledWith(ctx, logement);
|
|
82
|
+
expect(apportGratuitService.apportSolaire).toHaveBeenCalledWith(ctx, logement);
|
|
83
|
+
expect(apportGratuitService.apportInterne).toHaveBeenCalledWith(ctx, logement);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { inject } from 'dioma';
|
|
2
|
+
import { SurfaceSudEquivalenteService } from '../surface-sud-equivalente.service.js';
|
|
3
|
+
import { mois_liste } from '../../../../../utils.js';
|
|
4
|
+
import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Calcul des apports gratuits
|
|
8
|
+
* Chapitre 6 Détermination des apports gratuits
|
|
9
|
+
*
|
|
10
|
+
* Methode_de_calcul_3CL_DPE_2021 - Page 42
|
|
11
|
+
* Octobre 2021
|
|
12
|
+
* @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
|
|
13
|
+
*/
|
|
14
|
+
export class ApportGratuitService {
|
|
15
|
+
/**
|
|
16
|
+
* @type {FrTvStore}
|
|
17
|
+
*/
|
|
18
|
+
#frTvStore;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @type {SurfaceSudEquivalenteService}
|
|
22
|
+
*/
|
|
23
|
+
#surfaceSudEquivalenteService;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param frTvStore {FrTvStore}
|
|
27
|
+
* @param surfaceSudEquivalenteService {SurfaceSudEquivalenteService}
|
|
28
|
+
*/
|
|
29
|
+
constructor(
|
|
30
|
+
frTvStore = inject(FrTvStore),
|
|
31
|
+
surfaceSudEquivalenteService = inject(SurfaceSudEquivalenteService)
|
|
32
|
+
) {
|
|
33
|
+
this.#frTvStore = frTvStore;
|
|
34
|
+
this.#surfaceSudEquivalenteService = surfaceSudEquivalenteService;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Apports solaires gratuits du logement
|
|
39
|
+
*
|
|
40
|
+
* @param ctx {Contexte}
|
|
41
|
+
* @param logement {Logement}
|
|
42
|
+
* @returns {number}
|
|
43
|
+
*/
|
|
44
|
+
apportSolaire(ctx, logement) {
|
|
45
|
+
const clim = logement.climatisation_collection?.climatisation || [];
|
|
46
|
+
|
|
47
|
+
return mois_liste.reduce(
|
|
48
|
+
(acc, mois) => {
|
|
49
|
+
acc.apport_solaire_ch += this.apportSolaireMois(
|
|
50
|
+
ctx,
|
|
51
|
+
logement.enveloppe,
|
|
52
|
+
mois,
|
|
53
|
+
this.#frTvStore.getData(
|
|
54
|
+
'e',
|
|
55
|
+
ctx.altitude.value,
|
|
56
|
+
ctx.zoneClimatique.value,
|
|
57
|
+
mois,
|
|
58
|
+
ctx.inertie.ilpa
|
|
59
|
+
)
|
|
60
|
+
);
|
|
61
|
+
if (clim.length > 0) {
|
|
62
|
+
acc.apport_solaire_fr += this.apportSolaireMois(
|
|
63
|
+
ctx,
|
|
64
|
+
logement.enveloppe,
|
|
65
|
+
mois,
|
|
66
|
+
this.#frTvStore.getData('e_fr_28', ctx.altitude.value, ctx.zoneClimatique.value, mois)
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return acc;
|
|
70
|
+
},
|
|
71
|
+
{ apport_solaire_ch: 0, apport_solaire_fr: 0 }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Apports internes gratuits du logement
|
|
77
|
+
*
|
|
78
|
+
* @param ctx {Contexte}
|
|
79
|
+
* @param logement {Logement}
|
|
80
|
+
* @returns {number}
|
|
81
|
+
*/
|
|
82
|
+
apportInterne(ctx, logement) {
|
|
83
|
+
const clim = logement.climatisation_collection?.climatisation || [];
|
|
84
|
+
|
|
85
|
+
return mois_liste.reduce(
|
|
86
|
+
(acc, mois) => {
|
|
87
|
+
acc.apport_interne_ch += this.apportInterneMois(
|
|
88
|
+
ctx,
|
|
89
|
+
this.#frTvStore.getData(
|
|
90
|
+
'nref19',
|
|
91
|
+
ctx.altitude.value,
|
|
92
|
+
ctx.zoneClimatique.value,
|
|
93
|
+
mois,
|
|
94
|
+
ctx.inertie.ilpa
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
if (clim.length > 0) {
|
|
98
|
+
acc.apport_interne_fr += this.apportInterneMois(
|
|
99
|
+
ctx,
|
|
100
|
+
this.#frTvStore.getData('nref28', ctx.altitude.value, ctx.zoneClimatique.value, mois)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return acc;
|
|
104
|
+
},
|
|
105
|
+
{ apport_interne_ch: 0, apport_interne_fr: 0 }
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Apports solaires pour un mois donné
|
|
111
|
+
*
|
|
112
|
+
* @param ctx {Contexte}
|
|
113
|
+
* @param enveloppe {Enveloppe}
|
|
114
|
+
* @param mois {string}
|
|
115
|
+
* @param e {number} ensoleillement reçu, pour le mois, par une paroi verticale orientée au sud en absence d'ombrage (kWh/m²)
|
|
116
|
+
* @returns {number}
|
|
117
|
+
*/
|
|
118
|
+
apportSolaireMois(ctx, enveloppe, mois, e) {
|
|
119
|
+
return 1000 * this.#surfaceSudEquivalenteService.ssdMois(ctx, enveloppe, mois) * e;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Apports internes dans le logement pour un mois donné
|
|
124
|
+
* Les apports internes de chaleur dus aux équipements prennent en compte l’ensemble des équipements
|
|
125
|
+
* « mobiliers » (cuisson, audiovisuel, informatique, lavage, froid, appareils ménagers)
|
|
126
|
+
*
|
|
127
|
+
* @param ctx {Contexte}
|
|
128
|
+
* @param nref {number} nombre d’heures de chauffage pour le mois
|
|
129
|
+
* @returns {number}
|
|
130
|
+
*/
|
|
131
|
+
apportInterneMois(ctx, nref) {
|
|
132
|
+
return ((3.18 + 0.34) * ctx.surfaceHabitable + 90 * (132 / 168) * ctx.nadeq) * nref;
|
|
133
|
+
}
|
|
134
|
+
}
|