@open3cl/engine 1.0.0

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 (85) hide show
  1. package/10_besoin_fr.js +76 -0
  2. package/10_clim.js +45 -0
  3. package/11_besoin_ecs.js +25 -0
  4. package/11_ecs.js +95 -0
  5. package/11_nadeq.js +87 -0
  6. package/11_nadeq.spec.js +55 -0
  7. package/12.4_pac.js +54 -0
  8. package/13.2_generateur_combustion.js +295 -0
  9. package/13.2_generateur_combustion_bouilleur.js +173 -0
  10. package/13.2_generateur_combustion_ch.js +195 -0
  11. package/13.2_generateur_combustion_chaudiere.js +151 -0
  12. package/13.2_generateur_pac.js +36 -0
  13. package/13_rendement_distribution_ecs.js +12 -0
  14. package/14_generateur_ecs.js +388 -0
  15. package/15_conso_aux.js +257 -0
  16. package/16.2_production_enr.js +328 -0
  17. package/16.2_production_enr.spec.js +251 -0
  18. package/16_conso_eclairage.js +37 -0
  19. package/2021_04_13_confort_ete.js +61 -0
  20. package/2021_04_13_qualite_isolation.js +174 -0
  21. package/3.1_b.js +141 -0
  22. package/3.2.1_mur.js +331 -0
  23. package/3.2.1_mur.spec.js +46 -0
  24. package/3.2.2_plancher_bas.js +259 -0
  25. package/3.2.2_plancher_bas.spec.js +88 -0
  26. package/3.2.3_plancher_haut.js +158 -0
  27. package/3.3.1.4_porte.js +32 -0
  28. package/3.3_baie_vitree.js +308 -0
  29. package/3.3_baie_vitree.spec.js +333 -0
  30. package/3.4_pont_thermique.js +463 -0
  31. package/3_deperdition.js +258 -0
  32. package/4_ventilation.js +197 -0
  33. package/5_conso_ventilation.js +127 -0
  34. package/6.1_apport_gratuit.js +61 -0
  35. package/6.1_apport_gratuit.spec.js +181 -0
  36. package/6.2_surface_sud_equivalente.js +109 -0
  37. package/7_inertie.js +178 -0
  38. package/7_inertie.spec.js +263 -0
  39. package/8_intermittence.js +5 -0
  40. package/9_besoin_ch.js +198 -0
  41. package/9_chauffage.js +291 -0
  42. package/9_chauffage.spec.js +101 -0
  43. package/9_conso_ch.js +95 -0
  44. package/9_conso_ch.spec.js +255 -0
  45. package/9_emetteur_ch.js +122 -0
  46. package/9_generateur_ch.js +230 -0
  47. package/9_generateur_ch.spec.js +87 -0
  48. package/README.md +43 -0
  49. package/apport_et_besoin.js +55 -0
  50. package/conso.js +529 -0
  51. package/conso.spec.js +90 -0
  52. package/core/assets/domain/add-additionnal-ue-values-tables.js +57 -0
  53. package/core/assets/domain/synchronize-assets.js +29 -0
  54. package/core/assets/domain/synchronize-assets.spec.js +37 -0
  55. package/core/assets/domain/synchronize-c1-tables.js +61 -0
  56. package/core/assets/domain/synchronize-c1-tables.spec.js +35 -0
  57. package/core/assets/domain/synchronize-dpe-ges-limit-values-tables.js +73 -0
  58. package/core/assets/domain/synchronize-dpe-ges-limit-values-tables.spec.js +72 -0
  59. package/core/assets/domain/synchronize-enum-tables.js +77 -0
  60. package/core/assets/domain/synchronize-enum-tables.spec.js +31 -0
  61. package/core/assets/domain/synchronize-solicitations-tables.js +72 -0
  62. package/core/assets/domain/synchronize-solicitations-tables.spec.js +47 -0
  63. package/core/assets/domain/synchronize-valeur-tables.js +146 -0
  64. package/core/assets/domain/synchronize-valeur-tables.spec.js +54 -0
  65. package/core/conf/infrastructure/application.config.js +33 -0
  66. package/core/file/infrastructure/adapter/file.store.js +75 -0
  67. package/core/file/infrastructure/adapter/file.store.spec.js +30 -0
  68. package/core/tv/infrastructure/assets/additional-ue-values.js +69 -0
  69. package/core/tv/infrastructure/tvs.store.js +40 -0
  70. package/core/tv/infrastructure/tvs.store.spec.js +34 -0
  71. package/core/util/infrastructure/object-util.js +23 -0
  72. package/core/util/infrastructure/object-util.spec.js +25 -0
  73. package/engine.js +503 -0
  74. package/enums.js +1155 -0
  75. package/ficheTechnique.js +86 -0
  76. package/ficheTechnique.spec.js +181 -0
  77. package/index.js +4 -0
  78. package/package.json +87 -0
  79. package/tv/18.2_sollicitations_ext.ods +0 -0
  80. package/tv/18.5_c1.ods +0 -0
  81. package/tv/dpe_ges_limit_values.ods +0 -0
  82. package/tv.js +80811 -0
  83. package/tvs.d.ts +7 -0
  84. package/utils.js +500 -0
  85. package/utils.spec.js +36 -0
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Open3CL
2
+
3
+ Le méthode 3CL, décrite dans [ce PDF](https://rt-re-batiment.developpement-durable.gouv.fr/IMG/pdf/consolide_annexe_1_arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf), est la base de calcul pour les DPE.
4
+
5
+ Open3CL est un projet d'exploration pour mieux comprendre le DPE et la méthode de calcul 3CL, il est encore en développement, veuillez suivre [la progression ici](./test/).
6
+
7
+ ## Modèle de données
8
+
9
+ Les DPE dans la base de l'ademe sont au format XML. Open3CL fonctionne en json, car c'est un format plus simple pour travailler au quotidien. Le fichier [xml_to_json.js](./test/xml_to_json.js) permet de transformer un DPE xml en format json utilisable par Open3CL.
10
+
11
+ ## Ressources
12
+
13
+ - [PDF Méthode 3CL v1.3](https://rt-re-batiment.developpement-durable.gouv.fr/IMG/pdf/consolide_annexe_1_arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf)
14
+ - [Gitlab Observatoire DPE](https://gitlab.com/observatoire-dpe/observatoire-dpe/-/blob/master/README.md)
15
+ - [Légifrance 13/04/2021 ajout d'indicateur de confort thermique dans la sortie du DPE](https://www.legifrance.gouv.fr/download/pdf?id=doxMrRr0wbfJVvtWjfDP4qE7zNsiFZL-4wqNyqoY-CA=)
16
+ - [Légifrance 13/04/2021 valeurs GES](https://www.legifrance.gouv.fr/download/pdf?id=doxMrRr0wbfJVvtWjfDP4gHzzERt1iX0PtobthCE6A0=)
17
+ - [CSTB Procédure de certification](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjH-fG2-s7_AhXLaqQEHTP8CwMQFnoECA4QAQ&url=https%3A%2F%2Frt-re-batiment.developpement-durable.gouv.fr%2FIMG%2Fpdf%2Freglement_evaluation_logiciel_dpe_2021_-_audit_energetique-13122022_v2.pdf&usg=AOvVaw3SWv8drhqbgMMT8K9m6a2C&opi=89978449)
18
+ - [Valeurs des étiquettes énergétiques](https://docs.google.com/spreadsheets/d/1QVXUOLP8aJukA-PLBGyVB0ZJTWmLEE1WbflXUfsT_jU/edit#gid=0)
19
+
20
+ ## Quelques DPE intéressants
21
+
22
+ En travaillant sur les DPE je suis tombé sur quelques cas de DPE intéressants
23
+
24
+ - `2307E3075089A` chaudiere a condensation + climatiseur
25
+ - `2344E2258429L` DPE generé a partir des données immeuble
26
+ - `2362E3036179P` poele a charbon
27
+ - `2369E2991011Q` 1 radiateur à gaz + fenetres avec masques lointains
28
+ - `2387E0402213E` methode_application 'maison_individuelle' mais les portes sont saisie depuis une étude rt2012/rt2020
29
+ - `2387E0576340J` 2 gen ch
30
+ - `2387E0888781I` inertie lourde + paroi anciennes (tableaux de valeurs différents)
31
+ - `2387E1742056P` 2 emetteur ch
32
+ - `2387E2058698D` ventil hybride
33
+ - `2387E2603968B` inertie lourde + parois ancienne (différentes periode de chauffe)
34
+ - `2387E2899635W` 2 installation_ch
35
+ - `2387E2923777K` pas d’ECS, pas de portes
36
+ - `2387E3074987E` bouclage ECS
37
+ - `2387E3092820B` pas de pancher_haut
38
+ - `2387E3103131Q` Analysimmo 4.1.1 incohérence ventil calculée comme si presence_joint_menuiserie=1 alors qu’aucune menuiserie n’a de joints
39
+ - `2387E3103505A` Analysimmo 4.1.1 incohérence pont thermique, PB considéré pont ITI+ITE ??
40
+ - `2187E1039187C` toiture terrasse
41
+ - `2387E0291550X` probleme ubat/uph comble amenagés
42
+ - `2287E1724516Y` pour un meme generateur, position_volume_chauffe = 0 ou 1 selon si c'est le gen_ecs ou le gen_ch
43
+ - `2387E3092820B`, `2287E1043883T` et plein d'autres dpe. Le diagnostiqueur override la valeur forfaitaire de pveil pour le mettre a 0 car il n'y a pas de veilleuse sur la chaudiere, or pour le moteur il n'y a aucun moyen de savoir si donnee_intermediaire.pveil a ete saisi ou s'il faut aller chercher une valeur dans le tableau.
@@ -0,0 +1,55 @@
1
+ import enums from './enums.js';
2
+ import { calc_sse } from './6.2_surface_sud_equivalente.js';
3
+ import calc_besoin_fr from './10_besoin_fr.js';
4
+ import calc_besoin_ecs from './11_besoin_ecs.js';
5
+ import { Nadeq } from './11_nadeq.js';
6
+ import { calc_ai, calc_as } from './6.1_apport_gratuit.js';
7
+
8
+ const nadeqService = new Nadeq();
9
+
10
+ export default function calc_apport_et_besoin(
11
+ logement,
12
+ th,
13
+ ecs,
14
+ clim,
15
+ Sh,
16
+ Nb_lgt,
17
+ GV,
18
+ ilpa,
19
+ ca_id,
20
+ zc_id
21
+ ) {
22
+ const zc = enums.zone_climatique[zc_id];
23
+ const ca = enums.classe_altitude[ca_id];
24
+
25
+ const enveloppe = logement.enveloppe;
26
+ const inertie = enums.classe_inertie[enveloppe.inertie.enum_classe_inertie_id];
27
+
28
+ const bv = enveloppe.baie_vitree_collection.baie_vitree;
29
+ const ets = enveloppe.ets_collection.ets;
30
+
31
+ const nadeq = nadeqService.calculateNadeq(logement);
32
+
33
+ const besoin_ecs = calc_besoin_ecs(ca, zc, nadeq);
34
+ const besoin_fr = calc_besoin_fr(ca, zc, Sh, nadeq, GV, inertie, bv, ets);
35
+ const apport_interne = calc_ai(ilpa, ca, zc, Sh, nadeq);
36
+ const apport_solaire = calc_as(ilpa, ca, zc, bv, ets);
37
+
38
+ if (clim.length === 0) {
39
+ besoin_fr.besoin_fr = 0;
40
+ besoin_fr.besoin_fr_depensier = 0;
41
+ apport_interne.apport_interne_fr = 0;
42
+ apport_solaire.apport_solaire_fr = 0;
43
+ }
44
+
45
+ return {
46
+ nadeq,
47
+ v40_ecs_journalier: nadeq * 56,
48
+ v40_ecs_journalier_depensier: nadeq * 79,
49
+ surface_sud_equivalente: calc_sse(ca, zc, bv, ets),
50
+ ...besoin_ecs,
51
+ ...apport_interne,
52
+ ...apport_solaire,
53
+ ...besoin_fr
54
+ };
55
+ }
package/conso.js ADDED
@@ -0,0 +1,529 @@
1
+ import enums from './enums.js';
2
+ import calc_conso_eclairage from './16_conso_eclairage.js';
3
+ import tvs from './tv.js';
4
+ import { tv } from './utils.js';
5
+
6
+ const coef_ep = {
7
+ 'électricité ch': 2.3,
8
+ 'électricité ecs': 2.3,
9
+ 'électricité fr': 2.3,
10
+ 'électricité éclairage': 2.3,
11
+ 'électricité auxiliaire': 2.3
12
+ };
13
+
14
+ // 31 mars 2021
15
+ // https://www.legifrance.gouv.fr/download/pdf?id=doxMrRr0wbfJVvtWjfDP4gHzzERt1iX0PtobthCE6A0=
16
+ const coef_ges = {
17
+ 'bois – bûches': 0.03,
18
+ 'bois – granulés (pellets) ou briquettes': 0.03,
19
+ 'bois – plaquettes forestières': 0.024,
20
+ 'bois – plaquettes d’industrie': 0.024,
21
+ 'gaz naturel': 0.227,
22
+ 'fioul domestique': 0.324,
23
+ charbon: 0.385,
24
+ propane: 0.272,
25
+ butane: 0.272,
26
+ gpl: 0.272,
27
+ "électricité d'origine renouvelable utilisée dans le bâtiment": 0,
28
+ 'électricité ch': 0.079,
29
+ 'électricité ecs': 0.065,
30
+ 'électricité fr': 0.064,
31
+ 'électricité éclairage': 0.069,
32
+ 'électricité auxiliaire': 0.064
33
+ };
34
+
35
+ // annexe 7
36
+ // https://www.legifrance.gouv.fr/download/file/doxMrRr0wbfJVvtWjfDP4qE7zNsiFZL-4wqNyqoY-CA=/JOE_TEXTE
37
+ const coef_cout = {
38
+ 'fioul domestique': 0.09142,
39
+ 'réseau de chauffage urbain': 0.0787,
40
+ propane: 0.14305,
41
+ butane: 0.20027,
42
+ charbon: 0.02372,
43
+ 'bois – granulés (pellets) ou briquettes': 0.05991,
44
+ 'bois – bûches': 0.03201,
45
+ 'bois – plaquettes forestières': 0.03201,
46
+ 'bois – plaquettes d’industrie': 0.03201,
47
+ // https://www.legifrance.gouv.fr/download/pdf?id=7hpbVyq228foxHzNM7WleDImAyXlPNb9zULelSY01V8=
48
+ 'gaz naturel': cout_gaz_naturel,
49
+ "électricité d'origine renouvelable utilisée dans le bâtiment": cout_electricite,
50
+ 'électricité ch': cout_electricite,
51
+ 'électricité ecs': cout_electricite,
52
+ 'électricité fr': cout_electricite,
53
+ 'électricité éclairage': cout_electricite,
54
+ 'électricité auxiliaire': cout_electricite
55
+ };
56
+
57
+ /**
58
+ * Fonction utilitaire pour générer la clef à utiliser pour la table `coef_ges`.
59
+ * Le type_energie 'électricté' nécessite un suffixe : en fonction la destination d'usage,
60
+ * le coefficient est différent.
61
+ *
62
+ * @param type_energie {string} label de l'enum type_energie
63
+ * @param destination {'ch' | 'ecs' | 'éclairage'}
64
+ * @return {string} la clef à utiliser pour récupérer le coefficient depuis la table `coef_ges`
65
+ */
66
+ function getCoefKey(type_energie, destination) {
67
+ if (type_energie === 'électricité') {
68
+ if (!['ch', 'ecs', 'éclairage'].includes(destination)) {
69
+ console.error(`Type d'électricité inconnu: ${destination}`);
70
+ }
71
+ return `électricité ${destination}`;
72
+ }
73
+ return type_energie;
74
+ }
75
+
76
+ function cout_gaz_naturel(cef) {
77
+ if (cef < 5009) return 0.11121 * cef;
78
+ else if (cef < 50055) return 230 + 0.06533 * cef;
79
+ else return 415 + 0.06164 * cef;
80
+ }
81
+
82
+ function cout_electricite(cef) {
83
+ if (cef < 1000) return 0.29007 * cef;
84
+ else if (cef < 2500) return 149 + 0.14066 * cef;
85
+ else if (cef < 5000) return 122 + 0.15176 * cef;
86
+ else if (cef < 15000) return 94 + 0.15735 * cef;
87
+ else return 56 + 0.15989 * cef;
88
+ }
89
+
90
+ function getConso(coef, type_energie, conso) {
91
+ // is coef is a function, execute it
92
+ if (!coef) return conso;
93
+ const coef_val = coef[type_energie];
94
+ if (typeof coef_val === 'function') {
95
+ const val = coef_val(conso);
96
+ return val;
97
+ }
98
+ if (coef_val) return coef_val * conso;
99
+ return conso;
100
+ }
101
+
102
+ /**
103
+ * Récupération du coefficient d'émission GES pour le générateur
104
+ * @param gen_ch {GenerateurChauffageItem||GenerateurEcsItem}
105
+ * @param suffix {'ch'|'ecs'}
106
+ * @returns {number}
107
+ */
108
+ function getGesCoeffForGenerateur(gen_ch, suffix) {
109
+ const typeEnergie = getTypeEnergie(gen_ch.donnee_entree, suffix);
110
+
111
+ /**
112
+ * Cas spécifique des réseaux de chaleur urbain qui ont des coefficients différents en fonction de réseau de distribution
113
+ */
114
+ if (typeEnergie === 'réseau de chauffage urbain') {
115
+ const identifiant_reseau = gen_ch.donnee_entree.identifiant_reseau_chaleur;
116
+
117
+ if (identifiant_reseau) {
118
+ const row = tv('reseau_chaleur_2022', { identifiant_reseau });
119
+
120
+ if (row) {
121
+ return row.contenu_co2_acv;
122
+ } else {
123
+ console.error(`
124
+ Aucun coefficient GES trouvé pour le réseau de chaleur ${identifiant_reseau}
125
+ `);
126
+ }
127
+ } else {
128
+ // Prendre la valeur pour "AUTRES RESEAUX DE CHALEUR"
129
+ return 0.385;
130
+ }
131
+ }
132
+
133
+ return coef_ges[typeEnergie] ?? 1;
134
+ }
135
+
136
+ export default function calc_conso(
137
+ Sh,
138
+ zc_id,
139
+ ca_id,
140
+ vt,
141
+ ch,
142
+ ecs,
143
+ fr,
144
+ prorataECS,
145
+ prorataChauffage
146
+ ) {
147
+ const gen_ch = ch.reduce((acc, ch) => {
148
+ const generateur_chauffage = ch.generateur_chauffage_collection.generateur_chauffage;
149
+ generateur_chauffage.forEach((value) => {
150
+ // S'il existe une clé de repartition de chauffage, utilisation de celle-ci pour répartir la conso chauffage collectif à l'appartement
151
+ if (ch.donnee_entree.cle_repartition_ch === 1) {
152
+ value.donnee_entree.cle_repartition_ch = prorataChauffage;
153
+ } else {
154
+ value.donnee_entree.cle_repartition_ch =
155
+ ch.donnee_entree.cle_repartition_ch || prorataChauffage;
156
+ }
157
+ value.donnee_entree.enum_methode_calcul_conso_id =
158
+ ch.donnee_entree.enum_methode_calcul_conso_id;
159
+ value.donnee_entree.enum_type_installation_id = ch.donnee_entree.enum_type_installation_id;
160
+ (value.donnee_utilisateur = value.donnee_utilisateur || {}).coeffEmissionGes =
161
+ getGesCoeffForGenerateur(value, 'ch');
162
+ });
163
+ return acc.concat(generateur_chauffage);
164
+ }, []);
165
+
166
+ const gen_ecs = ecs.reduce((acc, ecs) => {
167
+ const generateur_ecs = ecs.generateur_ecs_collection.generateur_ecs;
168
+ if (prorataECS === 1) {
169
+ // S'il existe une clé de repartition ECS, utilisation de celle-ci pour répartir la conso ECS collective à l'appartement
170
+ generateur_ecs.forEach((value) => {
171
+ value.donnee_entree.cle_repartition_ecs =
172
+ (ecs.donnee_entree.cle_repartition_ecs || 1) * (ecs.donnee_entree.rdim || 1);
173
+ (value.donnee_utilisateur = value.donnee_utilisateur || {}).coeffEmissionGes =
174
+ getGesCoeffForGenerateur(value, 'ecs');
175
+ });
176
+ }
177
+ return acc.concat(generateur_ecs);
178
+ }, []);
179
+
180
+ const ret = {
181
+ ef_conso: calc_conso_pond(
182
+ Sh,
183
+ zc_id,
184
+ vt,
185
+ gen_ch,
186
+ gen_ecs,
187
+ fr,
188
+ 'conso',
189
+ null,
190
+ prorataECS,
191
+ prorataChauffage
192
+ ),
193
+ ep_conso: calc_conso_pond(
194
+ Sh,
195
+ zc_id,
196
+ vt,
197
+ gen_ch,
198
+ gen_ecs,
199
+ fr,
200
+ 'ep_conso',
201
+ coef_ep,
202
+ prorataECS,
203
+ prorataChauffage
204
+ ),
205
+ emission_ges: calc_conso_pond(
206
+ Sh,
207
+ zc_id,
208
+ vt,
209
+ gen_ch,
210
+ gen_ecs,
211
+ fr,
212
+ 'emission_ges',
213
+ coef_ges,
214
+ prorataECS,
215
+ prorataChauffage
216
+ ),
217
+ cout: calc_conso_pond(
218
+ Sh,
219
+ zc_id,
220
+ vt,
221
+ gen_ch,
222
+ gen_ecs,
223
+ fr,
224
+ 'cout',
225
+ coef_cout,
226
+ prorataECS,
227
+ prorataChauffage
228
+ )
229
+ };
230
+ ret.ep_conso.classe_bilan_dpe = classe_bilan_dpe(
231
+ ret.ep_conso.ep_conso_5_usages_m2,
232
+ zc_id,
233
+ ca_id,
234
+ Sh
235
+ );
236
+ ret.emission_ges.classe_emission_ges = classe_emission_ges(
237
+ ret.emission_ges.emission_ges_5_usages_m2,
238
+ zc_id,
239
+ ca_id,
240
+ Sh
241
+ );
242
+
243
+ const energie_ids = [];
244
+ // find all type_energies in gen_ch and gen_ecs
245
+ gen_ch.forEach((gen_ch) => {
246
+ const id = gen_ch.donnee_entree.enum_type_energie_id;
247
+ if (!energie_ids.includes(id)) energie_ids.push(id);
248
+ });
249
+ gen_ecs.forEach((gen_ecs) => {
250
+ const id = gen_ecs.donnee_entree.enum_type_energie_id;
251
+ if (!energie_ids.includes(id)) energie_ids.push(id);
252
+ });
253
+ if (!energie_ids.includes('1')) energie_ids.push('1');
254
+ // calculate calc_conso_pond for each energy type
255
+ ret.sortie_par_energie_collection = {};
256
+ ret.sortie_par_energie_collection.sortie_par_energie = energie_ids.reduce((acc, energie_id) => {
257
+ const type_energie = enums.type_energie[energie_id];
258
+ let vt_en, fr_en;
259
+ if (type_energie === 'électricité') {
260
+ vt_en = vt;
261
+ fr_en = fr;
262
+ } else {
263
+ vt_en = [];
264
+ fr_en = [];
265
+ }
266
+ const gen_ch_en = gen_ch.filter(
267
+ (gen_ch) => gen_ch.donnee_entree.enum_type_energie_id === energie_id
268
+ );
269
+ const gen_ecs_en = gen_ecs.filter(
270
+ (gen_ecs) => gen_ecs.donnee_entree.enum_type_energie_id === energie_id
271
+ );
272
+ let conso_en = calc_conso_pond(
273
+ Sh,
274
+ zc_id,
275
+ vt_en,
276
+ gen_ch_en,
277
+ gen_ecs_en,
278
+ fr_en,
279
+ '',
280
+ null,
281
+ prorataECS,
282
+ prorataChauffage
283
+ );
284
+ conso_en = {
285
+ conso_ch: conso_en._ch,
286
+ conso_ecs: conso_en._ecs,
287
+ conso_5_usages: conso_en._5_usages,
288
+ emission_ges_ch: conso_en._ch * coef_ges[getCoefKey(type_energie, 'ch')],
289
+ emission_ges_ecs: conso_en._ecs * coef_ges[getCoefKey(type_energie, 'ecs')],
290
+ emission_ges_5_usages: conso_en._5_usages * coef_ges[type_energie] // TODO elec
291
+ };
292
+ conso_en.enum_type_energie_id = energie_id;
293
+ return acc.concat(conso_en);
294
+ }, []);
295
+ return ret;
296
+ }
297
+
298
+ function classe_bilan_dpe(ep_conso_5_usages_m2, zc_id, ca_id, Sh) {
299
+ const ca = enums.classe_altitude[ca_id];
300
+
301
+ const cut = tvs.dpe_class_limit[ca][Math.round(Sh)] ?? [];
302
+
303
+ if (!ep_conso_5_usages_m2) return null;
304
+ if (ep_conso_5_usages_m2 < (cut['A'] ?? 70)) return 'A';
305
+ if (ep_conso_5_usages_m2 < (cut['B'] ?? 110)) return 'B';
306
+ if (ep_conso_5_usages_m2 < (cut['C'] ?? 180)) return 'C';
307
+ if (ep_conso_5_usages_m2 < (cut['D'] ?? 250)) return 'D';
308
+
309
+ const zc = enums.zone_climatique[zc_id];
310
+
311
+ if (['h1b', 'h1c', 'h2d'].includes(zc) && ca === 'supérieur à 800m') {
312
+ if (ep_conso_5_usages_m2 < (cut['E'] ?? 390)) return 'E';
313
+ if (ep_conso_5_usages_m2 < (cut['F'] ?? 500)) return 'F';
314
+ } else {
315
+ if (ep_conso_5_usages_m2 < (cut['E'] ?? 330)) return 'E';
316
+ if (ep_conso_5_usages_m2 < (cut['F'] ?? 420)) return 'F';
317
+ }
318
+ return 'G';
319
+ }
320
+
321
+ function classe_emission_ges(emission_ges_5_usages_m2, zc_id, ca_id, Sh) {
322
+ const ca = enums.classe_altitude[ca_id];
323
+
324
+ const cut = tvs.ges_class_limit[ca][Math.round(Sh)] ?? [];
325
+
326
+ if (!emission_ges_5_usages_m2) return null;
327
+ if (emission_ges_5_usages_m2 < (cut['A'] ?? 6)) return 'A';
328
+ if (emission_ges_5_usages_m2 < (cut['B'] ?? 11)) return 'B';
329
+ if (emission_ges_5_usages_m2 < (cut['C'] ?? 30)) return 'C';
330
+ if (emission_ges_5_usages_m2 < (cut['D'] ?? 50)) return 'D';
331
+
332
+ const zc = enums.zone_climatique[zc_id];
333
+
334
+ if (['h1b', 'h1c', 'h2d'].includes(zc) && ca === 'supérieur à 800m') {
335
+ if (emission_ges_5_usages_m2 < (cut['E'] ?? 80)) return 'E';
336
+ if (emission_ges_5_usages_m2 < (cut['F'] ?? 110)) return 'F';
337
+ } else {
338
+ if (emission_ges_5_usages_m2 < (cut['E'] ?? 70)) return 'E';
339
+ if (emission_ges_5_usages_m2 < (cut['F'] ?? 100)) return 'F';
340
+ }
341
+ return 'G';
342
+ }
343
+
344
+ /**
345
+ Calcul de la consommation globale d'ECS
346
+ * @param gen_ecs {Generateur_ecs_collection}
347
+ * @param field {string}
348
+ * @param coef {number}
349
+ * @param prorataECS {number}
350
+ * @param prefix {string}
351
+ * @returns {number}
352
+ */
353
+ function getEcsConso(gen_ecs, field, coef, prorataECS, prefix) {
354
+ return gen_ecs.reduce((acc, gen_ecs) => {
355
+ const conso = gen_ecs.donnee_intermediaire[field];
356
+ const typeEnergie = getTypeEnergie(gen_ecs.donnee_entree, 'ecs');
357
+
358
+ let coeffConsoEcs = { ...coef };
359
+
360
+ if (prefix === 'emission_ges') {
361
+ coeffConsoEcs[typeEnergie] = gen_ecs.donnee_utilisateur.coeffEmissionGes;
362
+ }
363
+
364
+ return (
365
+ acc +
366
+ getConso(coeffConsoEcs, typeEnergie, conso) *
367
+ (gen_ecs.donnee_entree.cle_repartition_ecs || prorataECS)
368
+ );
369
+ }, 0);
370
+ }
371
+
372
+ /**
373
+ * Calcul de la consommation globale de chauffage
374
+ * @param gen_ch {Generateur_chauffage_collection}
375
+ * @param field {string}
376
+ * @param coef {number}
377
+ * @param prorataChauffage {number}
378
+ * @param prefix {string}
379
+ * @returns {number}
380
+ */
381
+ function getChauffageConso(gen_ch, field, coef, prorataChauffage, prefix) {
382
+ return gen_ch.reduce((acc, gen_ch) => {
383
+ const conso = gen_ch.donnee_intermediaire[field];
384
+ const typeEnergie = getTypeEnergie(gen_ch.donnee_entree, 'ch');
385
+
386
+ // La clé de répartition n'est utilisée que dans le cadre des chauffages collectifs
387
+ const repartition =
388
+ gen_ch.donnee_entree.enum_type_installation_id !== '1'
389
+ ? gen_ch.donnee_entree.cle_repartition_ch || prorataChauffage
390
+ : prorataChauffage;
391
+
392
+ let coeffConsoChauffage = { ...coef };
393
+
394
+ if (prefix === 'emission_ges') {
395
+ coeffConsoChauffage[typeEnergie] = gen_ch.donnee_utilisateur.coeffEmissionGes;
396
+ }
397
+
398
+ return acc + getConso(coeffConsoChauffage, typeEnergie, conso) * repartition;
399
+ }, 0);
400
+ }
401
+
402
+ function calc_conso_pond(
403
+ Sh,
404
+ zc_id,
405
+ vt_list,
406
+ gen_ch,
407
+ gen_ecs,
408
+ fr_list,
409
+ prefix,
410
+ coef,
411
+ prorataECS,
412
+ prorataChauffage
413
+ ) {
414
+ const ret = {};
415
+ ret.auxiliaire_ventilation = vt_list.reduce((acc, vt) => {
416
+ let conso = vt.donnee_intermediaire.conso_auxiliaire_ventilation || 0;
417
+
418
+ if (vt.donnee_entree.cle_repartition_ventilation) {
419
+ conso *= vt.donnee_entree.cle_repartition_ventilation;
420
+ }
421
+
422
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
423
+ }, 0);
424
+
425
+ const conso_eclairage = calc_conso_eclairage(zc_id) * Sh;
426
+ ret.eclairage = getConso(coef, 'électricité éclairage', conso_eclairage);
427
+
428
+ // aux ch
429
+ ret.auxiliaire_generation_ch = gen_ch.reduce((acc, gen_ch) => {
430
+ const conso = gen_ch.donnee_intermediaire.conso_auxiliaire_generation_ch || 0;
431
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
432
+ }, 0);
433
+
434
+ ret.auxiliaire_generation_ch_depensier = gen_ch.reduce((acc, gen_ch) => {
435
+ const conso = gen_ch.donnee_intermediaire.conso_auxiliaire_generation_ch_depensier || 0;
436
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
437
+ }, 0);
438
+
439
+ ret.auxiliaire_distribution_ch = gen_ch.reduce((acc, gen_ch) => {
440
+ let conso = gen_ch.donnee_intermediaire.conso_auxiliaire_distribution_ch || 0;
441
+
442
+ /**
443
+ * enum_methode_calcul_conso_id
444
+ * 2 : 'installation collective rapportée à un logement : cas générateur à combustion virtuel ou ecs collective virtuelle'
445
+ */
446
+ if (
447
+ ['2', '4'].includes(gen_ch.donnee_entree.enum_methode_calcul_conso_id) &&
448
+ gen_ch.donnee_entree.cle_repartition_ch
449
+ ) {
450
+ conso *= gen_ch.donnee_entree.cle_repartition_ch;
451
+ }
452
+
453
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
454
+ }, 0);
455
+
456
+ ret.ch = getChauffageConso(gen_ch, 'conso_ch', coef, prorataChauffage, prefix);
457
+
458
+ ret.ch_depensier = getChauffageConso(
459
+ gen_ch,
460
+ 'conso_ch_depensier',
461
+ coef,
462
+ prorataChauffage,
463
+ prefix
464
+ );
465
+
466
+ ret.auxiliaire_generation_ecs = gen_ecs.reduce((acc, gen_ecs) => {
467
+ const conso = gen_ecs.donnee_intermediaire.conso_auxiliaire_generation_ecs || 0;
468
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
469
+ }, 0);
470
+
471
+ ret.auxiliaire_generation_ecs_depensier = gen_ecs.reduce((acc, gen_ecs) => {
472
+ const conso = gen_ecs.donnee_intermediaire.conso_auxiliaire_generation_ecs_depensier || 0;
473
+ return acc + getConso(coef, 'électricité auxiliaire', conso);
474
+ }, 0);
475
+
476
+ ret.auxiliaire_distribution_ecs = 0;
477
+
478
+ ret.ecs = getEcsConso(gen_ecs, 'conso_ecs', coef, prorataECS, prefix);
479
+
480
+ ret.ecs_depensier = getEcsConso(gen_ecs, 'conso_ecs_depensier', coef, prorataECS, prefix);
481
+
482
+ ret.fr = fr_list.reduce((acc, fr) => {
483
+ const conso = fr.donnee_intermediaire.conso_fr;
484
+ const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');
485
+
486
+ return acc + getConso(coef, typeEnergie, conso);
487
+ }, 0);
488
+
489
+ ret.fr_depensier = fr_list.reduce((acc, fr) => {
490
+ const conso = fr.donnee_intermediaire.conso_fr_depensier;
491
+ const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');
492
+
493
+ return acc + getConso(coef, typeEnergie, conso);
494
+ }, 0);
495
+
496
+ let tot_aux;
497
+ if (prefix === 'cout') tot_aux = 'total_auxiliaire';
498
+ else tot_aux = 'totale_auxiliaire';
499
+ ret[tot_aux] =
500
+ ret.auxiliaire_ventilation +
501
+ ret.auxiliaire_generation_ch +
502
+ ret.auxiliaire_generation_ecs +
503
+ ret.auxiliaire_distribution_ch +
504
+ ret.auxiliaire_distribution_ecs;
505
+ ret['5_usages'] = ret.ch + ret.ecs + ret.fr + ret[tot_aux] + ret.eclairage;
506
+ if (prefix !== 'cout') ret['5_usages_m2'] = Math.floor(ret['5_usages'] / Sh);
507
+
508
+ // add prefix_ to all ret keys
509
+ Object.keys(ret).forEach((key) => {
510
+ ret[`${prefix}_${key}`] = ret[key];
511
+ delete ret[key];
512
+ });
513
+ return ret;
514
+ }
515
+
516
+ /**
517
+ * Retourne le type d'énergie utilisé.
518
+ * 1 - Electricité par défaut si la donnée n'est pas définie
519
+ * @param donneeEntree {Donnee_entree}
520
+ * @param suffix {string} Suffix à ajouter au type électricité
521
+ * @return {string}
522
+ */
523
+ function getTypeEnergie(donneeEntree, suffix) {
524
+ let type_energie = enums.type_energie[donneeEntree.enum_type_energie_id || 1];
525
+
526
+ if (type_energie === 'électricité') type_energie = `électricité ${suffix}`;
527
+
528
+ return type_energie;
529
+ }