@open3cl/engine 1.6.0 → 1.6.2
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/10_besoin_fr.spec.js +122 -0
- package/10_clim.spec.js +116 -0
- package/11_besoin_ecs.spec.js +69 -0
- package/11_ecs.spec.js +282 -0
- package/11_nadeq.spec.js +37 -0
- package/12.4_pac.spec.js +131 -0
- package/13.2_generateur_combustion.js +2 -0
- package/13.2_generateur_combustion.spec.js +537 -0
- package/13.2_generateur_combustion_bouilleur.js +4 -1
- package/13.2_generateur_combustion_bouilleur.spec.js +74 -0
- package/13.2_generateur_combustion_ch.spec.js +323 -0
- package/13.2_generateur_combustion_chaudiere.spec.js +85 -0
- package/13.2_generateur_pac.spec.js +64 -0
- package/13_rendement_distribution_ecs.spec.js +38 -0
- package/14_generateur_ecs.js +4 -4
- package/14_generateur_ecs.spec.js +745 -0
- package/15_conso_aux.spec.js +225 -0
- package/16.2_production_enr.spec.js +188 -0
- package/16_conso_eclairage.spec.js +62 -0
- package/2021_04_13_confort_ete.spec.js +159 -0
- package/2021_04_13_qualite_isolation.js +1 -1
- package/2021_04_13_qualite_isolation.spec.js +286 -0
- package/3.1_b.js +1 -1
- package/3.1_b.spec.js +367 -0
- package/3.2.1_mur.spec.js +812 -39
- package/3.2.2_plancher_bas.spec.js +643 -78
- package/3.2.3_plancher_haut.spec.js +452 -0
- package/3.3.1.4_porte.spec.js +114 -0
- package/3.3_baie_vitree.spec.js +449 -295
- package/3.4_pont_thermique.spec.js +890 -0
- package/3_deperdition.spec.js +397 -0
- package/4_ventilation.js +1 -1
- package/4_ventilation.spec.js +406 -0
- package/5_conso_ventilation.spec.js +186 -0
- package/6.2_surface_sud_equivalente.spec.js +138 -0
- package/8_intermittence.spec.js +33 -0
- package/9_besoin_ch.js +2 -2
- package/9_besoin_ch.spec.js +381 -0
- package/9_chauffage.js +4 -0
- package/9_chauffage.spec.js +478 -92
- package/9_conso_ch.spec.js +502 -248
- package/9_emetteur_ch.spec.js +339 -0
- package/9_generateur_ch.spec.js +467 -81
- package/README.md +18 -9
- package/apport_et_besoin.spec.js +126 -0
- package/conso.js +1 -1
- package/conso.spec.js +471 -82
- package/core/assets/domain/add-additionnal-ue-values-tables.spec.js +53 -0
- package/core/assets/domain/synchronize-solicitations-tables.spec.js +25 -0
- package/core/assets/domain/synchronize-valeur-tables.spec.js +48 -0
- package/core/conf/infrastructure/application.config.spec.js +35 -0
- package/core/file/infrastructure/adapter/csv-parser.store.spec.js +31 -13
- package/core/file/infrastructure/adapter/file.store.spec.js +148 -12
- package/core/tv/infrastructure/assets/additional-ue-values.spec.js +36 -0
- package/core/util/infrastructure/object-util.spec.js +20 -0
- package/core/util/logger/log-service.js +16 -7
- package/core/util/logger/log-service.spec.js +101 -0
- package/dpe-sanitizer.service.spec.js +138 -0
- package/engine.js +7 -5
- package/engine.spec.js +854 -0
- package/enums.spec.js +46 -0
- package/features/dpe/domain/models/type-generateur.model.js +1 -2
- package/features/dpe/domain/models/type-generateur.model.spec.js +25 -0
- package/features/dpe/domain/models/type-habitation.model.spec.js +41 -0
- package/features/dpe/domain/models/type-stockage.model.spec.js +18 -0
- package/features/dpe/domain/models/type-ventilation.model.spec.js +19 -0
- package/features/dpe/infrastructure/ch/chTv.store.spec.js +4 -4
- package/features/dpe/infrastructure/enveloppe/baieVitreeTv.store.js +14 -2
- package/features/dpe/infrastructure/enveloppe/baieVitreeTv.store.spec.js +16 -0
- package/features/dpe/infrastructure/tv.store.js +28 -9
- package/features/dpe/infrastructure/tv.store.spec.js +44 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +2 -1
- package/features/engine/domain/apport_et_besoin/ch/besoin-ch.service.spec.js +18 -0
- package/features/engine/domain/apport_et_besoin/ch/perte-ch-recup.service.spec.js +33 -1
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +21 -1
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +41 -1
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +44 -1
- package/features/engine/domain/apport_et_besoin/surface-sud-equivalente.service.spec.js +2 -1
- package/features/engine/domain/ch/generateur-ch.service.js +2 -0
- package/features/engine/domain/ch/generateur-ch.service.spec.js +117 -2
- package/features/engine/domain/ch/installation-ch.service.spec.js +14 -0
- package/features/engine/domain/conso/froid/conso-froid.service.spec.js +82 -1
- package/features/engine/domain/constants.spec.js +14 -0
- package/features/engine/domain/contexte.builder.spec.js +21 -0
- package/features/engine/domain/ecs/generateur-ecs.service.spec.js +11 -0
- package/features/engine/domain/ecs/installation-ecs.service.spec.js +55 -2
- package/features/engine/domain/engine.service.spec.js +227 -4
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +124 -1
- package/features/engine/domain/enveloppe/deperdition-enveloppe.service.spec.js +270 -2
- package/features/engine/domain/enveloppe/deperdition.service.spec.js +141 -0
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +2 -1
- package/features/engine/domain/enveloppe/mur/deperdition-mur.service.spec.js +117 -1
- package/features/engine/domain/enveloppe/plancher_bas/deperdition-plancher-bas.service.spec.js +134 -1
- package/features/engine/domain/enveloppe/plancher_haut/deperdition-plancher-haut.service.spec.js +126 -1
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +18 -1
- package/features/engine/domain/enveloppe/porte/deperdition-porte.service.spec.js +2 -1
- package/features/engine/domain/enveloppe/ventilation/deperdition-ventilation.service.spec.js +67 -1
- package/features/normalizer/domain/dpe-normalizer.service.js +1 -1
- package/features/normalizer/domain/dpe-normalizer.service.spec.js +53 -2
- package/ficheTechnique.spec.js +26 -0
- package/index.spec.js +54 -0
- package/package.json +5 -2
- package/preprocessor/index.js +20 -0
- package/preprocessor/index.spec.js +15 -0
- package/tv.spec.js +38 -0
- package/utils.js +43 -1
- package/utils.spec.js +518 -2
- package/output.js +0 -1
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dépendances mockées uniquement pour `conso_aux_distribution_ch` :
|
|
5
|
+
* - `enums` : libellés de classe d'altitude / zone climatique ;
|
|
6
|
+
* - `tvs.nref19` : nombre d'heures de fonctionnement mensuel ;
|
|
7
|
+
* - `mois_liste` / `Tbase` : réduits à des valeurs contrôlées.
|
|
8
|
+
* `conso_aux_gen` n'utilise aucune de ces dépendances (calcul autonome).
|
|
9
|
+
*/
|
|
10
|
+
vi.mock('./enums.js', () => ({
|
|
11
|
+
default: {
|
|
12
|
+
classe_altitude: { 1: 'ca1' },
|
|
13
|
+
zone_climatique: { 1: 'h1a' }
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock('./tv.js', () => ({
|
|
18
|
+
default: {
|
|
19
|
+
nref19: { 0: { ca1: { Janvier: { h1a: 100 } } } }
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
vi.mock('./utils.js', () => ({
|
|
24
|
+
mois_liste: ['Janvier'],
|
|
25
|
+
Tbase: { ca1: { h1: -9 } }
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
const { conso_aux_gen, conso_aux_distribution_ch } = await import('./15_conso_aux.js');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 15.1 Consommation des auxiliaires de génération
|
|
32
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §15.1
|
|
33
|
+
*/
|
|
34
|
+
describe('conso_aux_gen - auxiliaires de génération', () => {
|
|
35
|
+
let di;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
di = { pn: 20000 };
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('chaudière gaz (chauffage) : facteurs G=20, H=1.6 appliqués', () => {
|
|
42
|
+
const de = { enum_type_generateur_ch_id: '90' };
|
|
43
|
+
conso_aux_gen(di, de, 'ch', 1000, 1200, 100);
|
|
44
|
+
expect(di.conso_auxiliaire_generation_ch).toBeCloseTo(2.6, 10);
|
|
45
|
+
expect(di.conso_auxiliaire_generation_ch_depensier).toBeCloseTo(3.12, 10);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('générateur hors des plages connues : consommation nulle (G=H=0)', () => {
|
|
49
|
+
const de = { enum_type_generateur_ch_id: '1' };
|
|
50
|
+
conso_aux_gen(di, de, 'ch', 1000, 1200, 100);
|
|
51
|
+
expect(di.conso_auxiliaire_generation_ch).toBe(0);
|
|
52
|
+
expect(di.conso_auxiliaire_generation_ch_depensier).toBe(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("chaudière bois : facteurs appliqués seulement en présence d'un ventilateur", () => {
|
|
56
|
+
const avecVentilateur = { pn: 20000 };
|
|
57
|
+
conso_aux_gen(
|
|
58
|
+
avecVentilateur,
|
|
59
|
+
{ enum_type_generateur_ch_id: '60', presenceVentilateur: 1 },
|
|
60
|
+
'ch',
|
|
61
|
+
1000,
|
|
62
|
+
1200,
|
|
63
|
+
100
|
|
64
|
+
);
|
|
65
|
+
expect(avecVentilateur.conso_auxiliaire_generation_ch).toBeCloseTo(14.165, 10);
|
|
66
|
+
|
|
67
|
+
const sansVentilateur = { pn: 20000 };
|
|
68
|
+
conso_aux_gen(
|
|
69
|
+
sansVentilateur,
|
|
70
|
+
{ enum_type_generateur_ch_id: '60', presenceVentilateur: 0 },
|
|
71
|
+
'ch',
|
|
72
|
+
1000,
|
|
73
|
+
1200,
|
|
74
|
+
100
|
|
75
|
+
);
|
|
76
|
+
expect(sansVentilateur.conso_auxiliaire_generation_ch).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('chaudière gaz avec Pn > 400 kW : puissance plafonnée à 400 kW', () => {
|
|
80
|
+
const diCap = { pn: 500000 };
|
|
81
|
+
conso_aux_gen(diCap, { enum_type_generateur_ch_id: '90' }, 'ch', 1000, 1200, 100);
|
|
82
|
+
expect(diCap.conso_auxiliaire_generation_ch).toBeCloseTo(1.65, 10);
|
|
83
|
+
expect(diCap.conso_auxiliaire_generation_ch_depensier).toBeCloseTo(1.584, 10);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('type ECS : aucun prorata de surface chauffée appliqué', () => {
|
|
87
|
+
const de = { enum_type_generateur_ecs_id: '50' };
|
|
88
|
+
conso_aux_gen(di, de, 'ecs', 800, 1000, 100);
|
|
89
|
+
expect(di.conso_auxiliaire_generation_ecs).toBeCloseTo(2.08, 10);
|
|
90
|
+
expect(di.conso_auxiliaire_generation_ecs_depensier).toBeCloseTo(2.6, 10);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('générateur à air chaud avec Pn > 300 kW : puissance plafonnée à 300 kW', () => {
|
|
94
|
+
// enum_type_generateur_ch_id = 50 => générateur à air chaud (H=4), G=0
|
|
95
|
+
const diAir = { pn: 500000 };
|
|
96
|
+
conso_aux_gen(diAir, { enum_type_generateur_ch_id: '50' }, 'ch', 1000, 1200, 100);
|
|
97
|
+
// g=0, h=4, pe plafonné à 300000 => Paux = 0 + 4*300 = 1200
|
|
98
|
+
// conso = (1 * (1200 * 1000 * 1)) / 300000 = 4
|
|
99
|
+
expect(diAir.conso_auxiliaire_generation_ch).toBeCloseTo(4, 10);
|
|
100
|
+
// depensier utilise di.pn (500000, non plafonné) : (1200 * 1200) / 500000 = 2.88
|
|
101
|
+
expect(diAir.conso_auxiliaire_generation_ch_depensier).toBeCloseTo(2.88, 10);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('chaudière bois avec ventilateur et Pn > 70 kW : puissance plafonnée à 70 kW', () => {
|
|
105
|
+
// enum_type_generateur_ch_id = 60 => chaudière bois (G=73.3, H=10.5)
|
|
106
|
+
const diBois = { pn: 100000 };
|
|
107
|
+
conso_aux_gen(
|
|
108
|
+
diBois,
|
|
109
|
+
{ enum_type_generateur_ch_id: '60', presenceVentilateur: 1 },
|
|
110
|
+
'ch',
|
|
111
|
+
1000,
|
|
112
|
+
1200,
|
|
113
|
+
100
|
|
114
|
+
);
|
|
115
|
+
// pe plafonné à 70000 => Paux = 73.3 + 10.5*70 = 808.3
|
|
116
|
+
// conso = (1 * (808.3 * 1000 * 1)) / 70000
|
|
117
|
+
expect(diBois.conso_auxiliaire_generation_ch).toBeCloseTo((808.3 * 1000) / 70000, 10);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('type de générateur inconnu (ni ch ni ecs) : facteurs nuls, consommation nulle', () => {
|
|
121
|
+
// Couvre la branche de repli `values[type] || []` de getFacteur
|
|
122
|
+
const diInconnu = { pn: 20000 };
|
|
123
|
+
conso_aux_gen(diInconnu, {}, 'autre', 1000, 1200, 100);
|
|
124
|
+
expect(diInconnu.conso_auxiliaire_generation_autre).toBe(0);
|
|
125
|
+
expect(diInconnu.conso_auxiliaire_generation_autre_depensier).toBe(0);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 15.2 Consommation des auxiliaires de distribution de chauffage
|
|
131
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §15.2
|
|
132
|
+
*/
|
|
133
|
+
describe('conso_aux_distribution_ch - auxiliaires de distribution', () => {
|
|
134
|
+
const emCh = [
|
|
135
|
+
{
|
|
136
|
+
donnee_entree: {
|
|
137
|
+
enum_type_emission_distribution_id: '10',
|
|
138
|
+
enum_temp_distribution_ch_id: '3'
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
test('puissance de circulateur plafonnée à 30 W pour une faible déperdition', () => {
|
|
144
|
+
const di = {};
|
|
145
|
+
// GV très faible => la puissance calculée reste sous le plancher de 30 W
|
|
146
|
+
conso_aux_distribution_ch(emCh, {}, di, {}, 100, 1, 1, '0', 1);
|
|
147
|
+
// Pcircem19 = 30 (plancher), nref19 = 100 => 30 * 100 / 1000 = 3
|
|
148
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeCloseTo(3, 10);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('une déperdition élevée augmente la consommation au-dessus du plancher', () => {
|
|
152
|
+
const di = {};
|
|
153
|
+
conso_aux_distribution_ch(emCh, {}, di, {}, 100, 1, 1, '0', 100000);
|
|
154
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeGreaterThan(3);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('émetteur plancher/plafond chauffant (deltaPem=15, Fcot=0,156)', () => {
|
|
158
|
+
// Type 6 => première liste : deltaPem=15, Fcot=0,156, deltaDim=7,5 (temp id 3)
|
|
159
|
+
const em = [
|
|
160
|
+
{
|
|
161
|
+
donnee_entree: {
|
|
162
|
+
enum_type_emission_distribution_id: '6',
|
|
163
|
+
enum_temp_distribution_ch_id: '3'
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
];
|
|
167
|
+
const di = {};
|
|
168
|
+
conso_aux_distribution_ch(em, {}, di, {}, 100, 1, 1, '0', 100000);
|
|
169
|
+
// valeur de référence de régression
|
|
170
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeCloseTo(215.1781621610199, 9);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('émetteur radiateur monotube (deltaPem=30)', () => {
|
|
174
|
+
// Type 24 => deuxième liste : deltaPem=30
|
|
175
|
+
const em = [
|
|
176
|
+
{
|
|
177
|
+
donnee_entree: {
|
|
178
|
+
enum_type_emission_distribution_id: '24',
|
|
179
|
+
enum_temp_distribution_ch_id: '3'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
];
|
|
183
|
+
const di = {};
|
|
184
|
+
conso_aux_distribution_ch(em, {}, di, {}, 100, 1, 1, '0', 100000);
|
|
185
|
+
// valeur de référence de régression
|
|
186
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeCloseTo(372.082418731648, 9);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('plusieurs émetteurs : Fcot forcé à 0,802 (cas le plus défavorable)', () => {
|
|
190
|
+
// Deux émetteurs de type plancher chauffant : sans le forçage, Fcot=0,156.
|
|
191
|
+
const em = [
|
|
192
|
+
{
|
|
193
|
+
donnee_entree: {
|
|
194
|
+
enum_type_emission_distribution_id: '6',
|
|
195
|
+
enum_temp_distribution_ch_id: '3'
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
donnee_entree: {
|
|
200
|
+
enum_type_emission_distribution_id: '6',
|
|
201
|
+
enum_temp_distribution_ch_id: '3'
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
];
|
|
205
|
+
const di = {};
|
|
206
|
+
conso_aux_distribution_ch(em, {}, di, {}, 100, 1, 1, '0', 100000);
|
|
207
|
+
// valeur de référence de régression (Fcot=0,802 malgré des planchers chauffants)
|
|
208
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeCloseTo(260.5604692803713, 9);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('température de distribution haute (id 4) : deltaDim = 15', () => {
|
|
212
|
+
const em = [
|
|
213
|
+
{
|
|
214
|
+
donnee_entree: {
|
|
215
|
+
enum_type_emission_distribution_id: '10',
|
|
216
|
+
enum_temp_distribution_ch_id: '4'
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
];
|
|
220
|
+
const di = {};
|
|
221
|
+
conso_aux_distribution_ch(em, {}, di, {}, 100, 1, 1, '0', 100000);
|
|
222
|
+
// valeur de référence de régression
|
|
223
|
+
expect(di.conso_auxiliaire_distribution_ch).toBeCloseTo(136.51553416032854, 9);
|
|
224
|
+
});
|
|
225
|
+
});
|
|
@@ -249,4 +249,192 @@ describe('production ENR unit tests', () => {
|
|
|
249
249
|
}
|
|
250
250
|
});
|
|
251
251
|
});
|
|
252
|
+
|
|
253
|
+
test('should reuse an existing donnee_intermediaire when computing conso elec ac', () => {
|
|
254
|
+
// Le noeud donnee_intermediaire préexiste : il doit être conservé (et non recréé)
|
|
255
|
+
const productionElecEnr = {
|
|
256
|
+
donnee_intermediaire: { valeur_existante: 42 },
|
|
257
|
+
panneaux_pv_collection: {
|
|
258
|
+
panneaux_pv: [{ nombre_module: 8, enum_orientation_pv_id: 1, enum_inclinaison_pv_id: 2 }]
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const productionElectricite = {};
|
|
263
|
+
const conso = {
|
|
264
|
+
ef_conso: {},
|
|
265
|
+
sortie_par_energie_collection: {
|
|
266
|
+
sortie_par_energie: [
|
|
267
|
+
{ enum_type_energie_id: '1', conso_5_usages: 1500, conso_ch: 1000, conso_ecs: 1500 }
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
productionENR.calculateConsoElecAc(
|
|
273
|
+
productionElectricite,
|
|
274
|
+
productionElecEnr,
|
|
275
|
+
conso,
|
|
276
|
+
1,
|
|
277
|
+
'maison',
|
|
278
|
+
10
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
// la clé préexistante est préservée, les champs calculés sont ajoutés
|
|
282
|
+
expect(productionElecEnr.donnee_intermediaire.valeur_existante).toBe(42);
|
|
283
|
+
expect(productionElecEnr.donnee_intermediaire.production_pv).toBe(2826.8015616000007);
|
|
284
|
+
expect(productionElecEnr.donnee_intermediaire.conso_elec_ac).toBeGreaterThan(0);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('should get ppv when panneaux_pv is a single object (not an array)', () => {
|
|
288
|
+
const productionElecEnr = {
|
|
289
|
+
panneaux_pv_collection: {
|
|
290
|
+
panneaux_pv: {
|
|
291
|
+
nombre_module: 8,
|
|
292
|
+
enum_orientation_pv_id: 1,
|
|
293
|
+
enum_inclinaison_pv_id: 2
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
// même résultat qu'avec un tableau à un élément
|
|
298
|
+
expect(productionENR.getPpv(productionElecEnr, 1)).toBe(2826.8015616000007);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('should update ep conso with a coeff ep override', () => {
|
|
302
|
+
const productionElectricite = {
|
|
303
|
+
conso_elec_ac_ecs: 200,
|
|
304
|
+
conso_elec_ac_ch: 150,
|
|
305
|
+
conso_elec_ac_fr: 100,
|
|
306
|
+
conso_elec_ac_eclairage: 250,
|
|
307
|
+
conso_elec_ac_auxiliaire: 300
|
|
308
|
+
};
|
|
309
|
+
const conso = {
|
|
310
|
+
ep_conso: {
|
|
311
|
+
ep_conso_ecs: 1000,
|
|
312
|
+
ep_conso_ch: 500,
|
|
313
|
+
ep_conso_fr: 800,
|
|
314
|
+
ep_conso_eclairage: 900,
|
|
315
|
+
ep_conso_totale_auxiliaire: 1250,
|
|
316
|
+
ep_conso_5_usages: 5000,
|
|
317
|
+
ep_conso_5_usages_m2: 100
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// coeff_ep_override = 2 : chaque poste est minoré de 2 * autoconso
|
|
322
|
+
productionENR.updateEPConso(productionElectricite, conso, 10, 2);
|
|
323
|
+
|
|
324
|
+
expect(conso.ep_conso).toStrictEqual({
|
|
325
|
+
ep_conso_ecs: 600, // 1000 - 2*200
|
|
326
|
+
ep_conso_ch: 200, // 500 - 2*150
|
|
327
|
+
ep_conso_fr: 600, // 800 - 2*100
|
|
328
|
+
ep_conso_eclairage: 400, // 900 - 2*250
|
|
329
|
+
ep_conso_totale_auxiliaire: 650, // 1250 - 2*300
|
|
330
|
+
ep_conso_5_usages: 3000, // 5000 - 2*1000
|
|
331
|
+
ep_conso_5_usages_m2: 300 // floor(3000 / 10)
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('should update ep conso with the default coeff ep (1.9) when no override', () => {
|
|
336
|
+
const productionElectricite = {
|
|
337
|
+
conso_elec_ac_ecs: 200,
|
|
338
|
+
conso_elec_ac_ch: 150,
|
|
339
|
+
conso_elec_ac_fr: 100,
|
|
340
|
+
conso_elec_ac_eclairage: 250,
|
|
341
|
+
conso_elec_ac_auxiliaire: 300
|
|
342
|
+
};
|
|
343
|
+
const conso = {
|
|
344
|
+
ep_conso: {
|
|
345
|
+
ep_conso_ecs: 1000,
|
|
346
|
+
ep_conso_ch: 500,
|
|
347
|
+
ep_conso_fr: 800,
|
|
348
|
+
ep_conso_eclairage: 900,
|
|
349
|
+
ep_conso_totale_auxiliaire: 1250,
|
|
350
|
+
ep_conso_5_usages: 5000,
|
|
351
|
+
ep_conso_5_usages_m2: 100
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// pas d'override => coefficient par défaut 1.9
|
|
356
|
+
productionENR.updateEPConso(productionElectricite, conso, 10);
|
|
357
|
+
|
|
358
|
+
expect(conso.ep_conso).toStrictEqual({
|
|
359
|
+
ep_conso_ecs: 620, // 1000 - 1.9*200
|
|
360
|
+
ep_conso_ch: 215, // 500 - 1.9*150
|
|
361
|
+
ep_conso_fr: 610, // 800 - 1.9*100
|
|
362
|
+
ep_conso_eclairage: 425, // 900 - 1.9*250
|
|
363
|
+
ep_conso_totale_auxiliaire: 680, // 1250 - 1.9*300
|
|
364
|
+
ep_conso_5_usages: 3100, // 5000 - 1.9*1000
|
|
365
|
+
ep_conso_5_usages_m2: 310 // floor(3100 / 10)
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test.each([
|
|
370
|
+
['une installation absente', null],
|
|
371
|
+
["l'absence de production photovoltaïque", { donnee_entree: { presence_production_pv: 0 } }]
|
|
372
|
+
])('calculateEnr retourne des autoconsommations nulles pour %s', (_label, productionElecEnr) => {
|
|
373
|
+
const conso = { ef_conso: {}, ep_conso: {} };
|
|
374
|
+
|
|
375
|
+
const ret = productionENR.calculateEnr(productionElecEnr, conso, 10, 'maison', 1, 100);
|
|
376
|
+
|
|
377
|
+
expect(ret).toStrictEqual({
|
|
378
|
+
production_pv: 0,
|
|
379
|
+
conso_elec_ac: 0,
|
|
380
|
+
conso_elec_ac_ch: 0,
|
|
381
|
+
conso_elec_ac_ecs: 0,
|
|
382
|
+
conso_elec_ac_fr: 0,
|
|
383
|
+
conso_elec_ac_eclairage: 0,
|
|
384
|
+
conso_elec_ac_auxiliaire: 0,
|
|
385
|
+
conso_elec_ac_autre_usage: 0
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test('calculateEnr calcule et applique les autoconsommations en présence de PV', () => {
|
|
390
|
+
const productionElecEnr = {
|
|
391
|
+
donnee_entree: { presence_production_pv: 1 },
|
|
392
|
+
panneaux_pv_collection: {
|
|
393
|
+
panneaux_pv: [{ nombre_module: 8, enum_orientation_pv_id: 1, enum_inclinaison_pv_id: 2 }]
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
const conso = {
|
|
397
|
+
ef_conso: {
|
|
398
|
+
conso_ecs: 1000,
|
|
399
|
+
conso_ch: 500,
|
|
400
|
+
conso_fr: 800,
|
|
401
|
+
conso_eclairage: 900,
|
|
402
|
+
conso_totale_auxiliaire: 1250,
|
|
403
|
+
conso_5_usages: 1500,
|
|
404
|
+
conso_5_usages_m2: 100
|
|
405
|
+
},
|
|
406
|
+
ep_conso: {
|
|
407
|
+
ep_conso_ecs: 3000,
|
|
408
|
+
ep_conso_ch: 1500,
|
|
409
|
+
ep_conso_fr: 2000,
|
|
410
|
+
ep_conso_eclairage: 1800,
|
|
411
|
+
ep_conso_totale_auxiliaire: 2500,
|
|
412
|
+
ep_conso_5_usages: 10000,
|
|
413
|
+
ep_conso_5_usages_m2: 100
|
|
414
|
+
},
|
|
415
|
+
sortie_par_energie_collection: {
|
|
416
|
+
sortie_par_energie: [
|
|
417
|
+
{ enum_type_energie_id: '1', conso_5_usages: 1500, conso_ch: 1000, conso_ecs: 1500 }
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const ret = productionENR.calculateEnr(productionElecEnr, conso, 10, 'maison', 1, 100);
|
|
423
|
+
|
|
424
|
+
// valeurs de référence de régression
|
|
425
|
+
expect(ret).toStrictEqual({
|
|
426
|
+
production_pv: 2826.8015616000007,
|
|
427
|
+
conso_elec_ac: 403.3632077277818,
|
|
428
|
+
conso_elec_ac_ch: 17.146151231786686,
|
|
429
|
+
conso_elec_ac_ecs: 64.29806711920007,
|
|
430
|
+
conso_elec_ac_fr: 171.46151231786683,
|
|
431
|
+
conso_elec_ac_eclairage: 38.57884027152004,
|
|
432
|
+
conso_elec_ac_auxiliaire: 0,
|
|
433
|
+
conso_elec_ac_autre_usage: 21.14245810055866
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// les consommations d'énergie finale sont bien minorées par l'autoconsommation
|
|
437
|
+
expect(conso.ef_conso.conso_ecs).toBeLessThan(1000);
|
|
438
|
+
expect(conso.ef_conso.conso_5_usages).toBeLessThan(1500);
|
|
439
|
+
});
|
|
252
440
|
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Le module ne dépend que du mapping enum_zone_climatique_id -> libellé de zone.
|
|
5
|
+
* On le mocke afin d'isoler le test du contenu réel de `enums`.
|
|
6
|
+
*/
|
|
7
|
+
vi.mock('./enums.js', () => ({
|
|
8
|
+
default: {
|
|
9
|
+
zone_climatique: {
|
|
10
|
+
1: 'h1a',
|
|
11
|
+
2: 'h1b',
|
|
12
|
+
3: 'h1c',
|
|
13
|
+
4: 'h2a',
|
|
14
|
+
5: 'h2b',
|
|
15
|
+
6: 'h2c',
|
|
16
|
+
7: 'h2d',
|
|
17
|
+
8: 'h3'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const { default: calc_conso_eclairage } = await import('./16_conso_eclairage.js');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 16.1 Consommation d'éclairage (Cecl)
|
|
26
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §16.1
|
|
27
|
+
*
|
|
28
|
+
* Cecl = (C * Pecl * Nh) / 1000 avec C = 0.9 (interrupteur) et Pecl = 1.4 W/m²
|
|
29
|
+
* Nh = nombre d'heures de fonctionnement de l'éclairage, fonction de la zone climatique.
|
|
30
|
+
*/
|
|
31
|
+
describe("Calcul de la consommation d'éclairage (Cecl)", () => {
|
|
32
|
+
// [enum_zone_climatique_id, libellé, Nh, Cecl attendu]
|
|
33
|
+
test.each([
|
|
34
|
+
['1', 'h1a', 1500, (0.9 * 1.4 * 1500) / 1000],
|
|
35
|
+
['2', 'h1b', 1445, (0.9 * 1.4 * 1445) / 1000],
|
|
36
|
+
['3', 'h1c', 1476, (0.9 * 1.4 * 1476) / 1000],
|
|
37
|
+
['4', 'h2a', 1500, (0.9 * 1.4 * 1500) / 1000],
|
|
38
|
+
['5', 'h2b', 1531, (0.9 * 1.4 * 1531) / 1000],
|
|
39
|
+
['6', 'h2c', 1566, (0.9 * 1.4 * 1566) / 1000],
|
|
40
|
+
['7', 'h2d', 1566, (0.9 * 1.4 * 1566) / 1000],
|
|
41
|
+
['8', 'h3', 1506, (0.9 * 1.4 * 1506) / 1000]
|
|
42
|
+
])(
|
|
43
|
+
'zone climatique %s (%s) : Nh=%d heures => Cecl attendu',
|
|
44
|
+
(zc_id, _libelle, _nh, cecl_attendu) => {
|
|
45
|
+
expect(calc_conso_eclairage(zc_id)).toBeCloseTo(cecl_attendu, 10);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
test('la consommation est identique pour deux zones ayant le même Nh (h1a et h2a)', () => {
|
|
50
|
+
expect(calc_conso_eclairage('1')).toBeCloseTo(calc_conso_eclairage('4'), 10);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("la consommation croît avec le nombre d'heures (h1b < h3 < h2c)", () => {
|
|
54
|
+
expect(calc_conso_eclairage('2')).toBeLessThan(calc_conso_eclairage('8'));
|
|
55
|
+
expect(calc_conso_eclairage('8')).toBeLessThan(calc_conso_eclairage('6'));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('retourne NaN pour un identifiant de zone climatique inconnu', () => {
|
|
59
|
+
// enums.zone_climatique[zc_id] est undefined => Nh[undefined] est undefined => NaN
|
|
60
|
+
expect(calc_conso_eclairage('99')).toBeNaN();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dépendances mockées pour isoler `calc_confort_ete` :
|
|
5
|
+
* - `enums.classe_inertie` : détermine le caractère « lourd » de l'inertie ;
|
|
6
|
+
* - `getKeyByValue` : réduit à un passe-plat renvoyant directement le libellé
|
|
7
|
+
* de confort (on assertera donc `enum_indicateur_confort_ete_id` = libellé) ;
|
|
8
|
+
* - `requestInput` : passe-plat lisant le champ demandé dans les données d'entrée.
|
|
9
|
+
*/
|
|
10
|
+
vi.mock('./enums.js', () => ({
|
|
11
|
+
default: {
|
|
12
|
+
classe_inertie: { 1: 'légère', 2: 'moyenne', 3: 'lourde', 4: 'très lourde' },
|
|
13
|
+
indicateur_confort_ete: { 1: 'insuffisant', 2: 'moyen', 3: 'bon' }
|
|
14
|
+
}
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock('./utils.js', () => ({
|
|
18
|
+
getKeyByValue: (object, value) => value,
|
|
19
|
+
requestInput: (de, du, field) => de[field]
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const { default: calc_confort_ete } = await import('./2021_04_13_confort_ete.js');
|
|
23
|
+
|
|
24
|
+
/** Fabrique une baie vitrée : `enum_orientation_id` sert au caractère traversant,
|
|
25
|
+
* `orientation` et `type_fermeture` à la protection solaire. */
|
|
26
|
+
function baie({ orientationId, orientation = 'sud', typeFermeture = 'volet' }) {
|
|
27
|
+
return {
|
|
28
|
+
donnee_entree: {
|
|
29
|
+
enum_orientation_id: orientationId,
|
|
30
|
+
orientation,
|
|
31
|
+
type_fermeture: typeFermeture
|
|
32
|
+
},
|
|
33
|
+
donnee_utilisateur: {}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Fabrique un plancher haut avec son type d'adjacence et d'isolation. */
|
|
38
|
+
function plancherHaut({ typeAdjacence = 'extérieur', typeIsolation = 'isolé' }) {
|
|
39
|
+
return {
|
|
40
|
+
donnee_entree: { type_adjacence: typeAdjacence, type_isolation: typeIsolation },
|
|
41
|
+
donnee_utilisateur: {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Indicateur de confort d'été
|
|
47
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - annexe confort d'été
|
|
48
|
+
*/
|
|
49
|
+
describe("calc_confort_ete - indicateur de confort d'été", () => {
|
|
50
|
+
test('inertie lourde + aspect traversant : niveau « bon »', () => {
|
|
51
|
+
// deux orientations distinctes => aspect_traversant = 1 ; inertie lourde = 1 => nv_bon = 2
|
|
52
|
+
const bv = [baie({ orientationId: '1' }), baie({ orientationId: '2' })];
|
|
53
|
+
const ph = [plancherHaut({ typeIsolation: 'isolé' })];
|
|
54
|
+
|
|
55
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
56
|
+
|
|
57
|
+
expect(ret.inertie_lourde).toBe(1);
|
|
58
|
+
expect(ret.aspect_traversant).toBe(1);
|
|
59
|
+
expect(ret.enum_indicateur_confort_ete_id).toBe('bon');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('inertie « très lourde » également considérée comme lourde', () => {
|
|
63
|
+
const bv = [baie({ orientationId: '1' }), baie({ orientationId: '2' })];
|
|
64
|
+
const ph = [plancherHaut({})];
|
|
65
|
+
|
|
66
|
+
const ret = calc_confort_ete('4', bv, ph);
|
|
67
|
+
|
|
68
|
+
expect(ret.inertie_lourde).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('une seule orientation : aspect non traversant', () => {
|
|
72
|
+
const bv = [baie({ orientationId: '1' }), baie({ orientationId: '1' })];
|
|
73
|
+
const ph = [plancherHaut({})];
|
|
74
|
+
|
|
75
|
+
const ret = calc_confort_ete('2', bv, ph);
|
|
76
|
+
|
|
77
|
+
expect(ret.aspect_traversant).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('inertie légère sans aspect traversant : niveau « moyen »', () => {
|
|
81
|
+
// nv_bon = 0 (< 2) mais protections OK => moyen
|
|
82
|
+
const bv = [baie({ orientationId: '1' })];
|
|
83
|
+
const ph = [plancherHaut({})];
|
|
84
|
+
|
|
85
|
+
const ret = calc_confort_ete('1', bv, ph);
|
|
86
|
+
|
|
87
|
+
expect(ret.inertie_lourde).toBe(0);
|
|
88
|
+
expect(ret.enum_indicateur_confort_ete_id).toBe('moyen');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("toiture non isolée donnant sur l'extérieur : niveau « insuffisant »", () => {
|
|
92
|
+
const bv = [baie({ orientationId: '1' }), baie({ orientationId: '2' })];
|
|
93
|
+
const ph = [plancherHaut({ typeAdjacence: 'extérieur', typeIsolation: 'non isolé' })];
|
|
94
|
+
|
|
95
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
96
|
+
|
|
97
|
+
expect(ret.isolation_toiture).toBe(0);
|
|
98
|
+
expect(ret.enum_indicateur_confort_ete_id).toBe('insuffisant');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("toiture d'isolation inconnue donnant sur l'extérieur : isolation nulle", () => {
|
|
102
|
+
const bv = [baie({ orientationId: '1' })];
|
|
103
|
+
const ph = [plancherHaut({ typeAdjacence: 'extérieur', typeIsolation: 'inconnu' })];
|
|
104
|
+
|
|
105
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
106
|
+
|
|
107
|
+
expect(ret.isolation_toiture).toBe(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('toiture non isolée mais non extérieure : isolation préservée', () => {
|
|
111
|
+
const bv = [baie({ orientationId: '1' }), baie({ orientationId: '2' })];
|
|
112
|
+
const ph = [plancherHaut({ typeAdjacence: 'local non chauffé', typeIsolation: 'non isolé' })];
|
|
113
|
+
|
|
114
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
115
|
+
|
|
116
|
+
expect(ret.isolation_toiture).toBe(1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('baie non nord sans fermeture : protection solaire nulle => « insuffisant »', () => {
|
|
120
|
+
const bv = [
|
|
121
|
+
baie({
|
|
122
|
+
orientationId: '1',
|
|
123
|
+
orientation: 'sud',
|
|
124
|
+
typeFermeture: 'abscence de fermeture pour la baie vitrée'
|
|
125
|
+
})
|
|
126
|
+
];
|
|
127
|
+
const ph = [plancherHaut({})];
|
|
128
|
+
|
|
129
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
130
|
+
|
|
131
|
+
expect(ret.protection_solaire_exterieure).toBe(0);
|
|
132
|
+
expect(ret.enum_indicateur_confort_ete_id).toBe('insuffisant');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('baie nord sans fermeture : ignorée, protection solaire préservée', () => {
|
|
136
|
+
const bv = [
|
|
137
|
+
baie({
|
|
138
|
+
orientationId: '1',
|
|
139
|
+
orientation: 'nord',
|
|
140
|
+
typeFermeture: 'abscence de fermeture pour la baie vitrée'
|
|
141
|
+
}),
|
|
142
|
+
baie({
|
|
143
|
+
orientationId: '2',
|
|
144
|
+
orientation: 'nord',
|
|
145
|
+
typeFermeture: 'abscence de fermeture pour la baie vitrée'
|
|
146
|
+
})
|
|
147
|
+
];
|
|
148
|
+
const ph = [plancherHaut({})];
|
|
149
|
+
|
|
150
|
+
const ret = calc_confort_ete('3', bv, ph);
|
|
151
|
+
|
|
152
|
+
expect(ret.protection_solaire_exterieure).toBe(1);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("le brasseur d'air est toujours absent (0) dans ce calcul", () => {
|
|
156
|
+
const ret = calc_confort_ete('3', [baie({ orientationId: '1' })], [plancherHaut({})]);
|
|
157
|
+
expect(ret.brasseur_air).toBe(0);
|
|
158
|
+
});
|
|
159
|
+
});
|