@open3cl/engine 1.0.14 → 1.0.16

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/4_ventilation.js CHANGED
@@ -156,7 +156,14 @@ export default function calc_ventilation(
156
156
  const Hsp = cg.hsp;
157
157
 
158
158
  tv_debits_ventilation(di, de, du);
159
- tv_q4pa_conv(di, de, cg, mur_list, ph_list, porte_list, bv_list);
159
+
160
+ // Pour les bâtiments qui ont fait l’objet d’une mesure d’étanchéité à l’air moins de deux ans avant le diagnostic, la valeur
161
+ // mesurée de Q4Paconv/m² peut être saisie.
162
+ if (de.q4pa_conv_saisi) {
163
+ di.q4pa_conv = de.q4pa_conv_saisi;
164
+ } else {
165
+ tv_q4pa_conv(di, de, cg, mur_list, ph_list, porte_list, bv_list);
166
+ }
160
167
 
161
168
  di.hvent = 0.34 * di.qvarep_conv * surface_ventile;
162
169
 
package/README.md CHANGED
@@ -1,22 +1,79 @@
1
- # Open3CL
2
-
3
- Open3CL est une librairie JavaScript open source, spécialement conçue pour faciliter le calcul des Diagnostics de Performance Énergétique (DPE). Elle implémente la norme définie dans [l'annexe 1 de l'arrêté du 31 mars 2021](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). Elle est destinée aux développeurs qui souhaitent intégrer des calculs énergétiques précis et conformes à la réglementation dans leurs applications.
4
-
5
- ## Fonctionnalités principales
6
-
7
- - **Calculs énergétiques** : Supporte les différentes méthodologies définies par la réglementation.
8
- - **Conformité** : Implémente la norme définie dans [l'annexe 1 de l'arrêté du 31 mars 2021](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).
9
- - **Performance** : Optimisée pour des calculs rapides sur de grands ensembles de données.
1
+ <a id="readme-top"></a>
2
+ [![Contributors][contributors-shield]][contributors-url]
3
+ [![Forks][forks-shield]][forks-url]
4
+ [![Stargazers][stars-shield]][stars-url]
5
+ [![Issues][issues-shield]][issues-url]
6
+ [![ GPL-3.0 license][license-shield]][license-url]
7
+
8
+ <br />
9
+ <div align="center">
10
+ <a href="https://open3cl.fr">
11
+ <img src="images/logo.png" alt="Logo" width="260" height="80">
12
+ </a>
13
+
14
+ <h3 align="center">Open3CL</h3>
15
+ Implémentation open source du moteur Open3CL de l'ADEME.
16
+ <p align="center">
17
+
18
+ ![Javascript][Javascript]
19
+
20
+ <br/>
21
+ <a href="https://github.com/Open3CL/issues/new?labels=bug&template=bug-report---.md">Créer un bug</a>
22
+ &middot;
23
+ <a href="https://github.com/Open3CL/issues/new?labels=enhancement&template=feature-request---.md">Créer une feature</a>
24
+ </p>
25
+ </div>
26
+
27
+ <details>
28
+ <summary>Sommaire</summary>
29
+ <ol>
30
+ <li>
31
+ <a href="#a-propos-du-projet">A propos du projet</a>
32
+ </li>
33
+ <li>
34
+ <a href="#demarrage">Démarrage</a>
35
+ <ul>
36
+ <li><a href="#pre-requis">Pre-requis</a></li>
37
+ <li><a href="#installation">Installation</a></li>
38
+ <li><a href="#documentation">Documentation</a></li>
39
+ </ul>
40
+ </li>
41
+ <li><a href="#usage">Usage</a></li>
42
+ <li><a href="#rapports">Rapports</a></li>
43
+ <li><a href="#roadmap">Roadmap</a></li>
44
+ <li><a href="#contribution">Contribution</a></li>
45
+ <li><a href="#license">License</a></li>
46
+ <li><a href="#contact">Contact</a></li>
47
+ <li><a href="#acknowledgments">Acknowledgments</a></li>
48
+ </ol>
49
+ </details>
50
+
51
+ ## A propos du projet
52
+
53
+ Open3CL est une librairie JavaScript open source, spécialement conçue pour faciliter le calcul des Diagnostics de Performance Énergétique (DPE).
54
+ Elle implémente la norme définie dans [l'annexe 1 de l'arrêté du 31 mars 2021](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). Elle est destinée aux développeurs qui souhaitent intégrer des calculs énergétiques précis et conformes à la réglementation dans leurs applications.
55
+
56
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
57
+
58
+ ## Démarrage
59
+
60
+ ### Pre-requis
61
+
62
+ Vous devez d'abord installer [NodeJS](https://nodejs.org/en) en version 20 ou supérieure.
63
+
64
+ ### Installation
65
+
66
+ ```sh
67
+ npm install @open3cl/engine
68
+ ```
10
69
 
11
- ## Installation
70
+ ### Documentation
12
71
 
13
- ```bash
14
- npm install @open3cl/engine
15
- ```
72
+ Lien à faire vers les wiki
16
73
 
17
- ## Exemple d'utilisation
74
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
18
75
 
19
- Voici un exemple basique montrant comment utiliser Open3CL pour calculer un DPE :
76
+ ## Utilisation
20
77
 
21
78
  ```javascript
22
79
  import { calcul_3cl } from 'open3cl';
@@ -47,58 +104,70 @@ const dpeData = {
47
104
  const result = calcul_3cl(dpeData);
48
105
  ```
49
106
 
50
- ## Documentation
51
-
52
- Vous pouvez consulter la documentation complète sur [l'annexe 1 de l'arrêté du 31 mars 2021](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) pour obtenir plus de détails sur l'utilisation des différents modules et fonctions.
53
-
54
- ## Ressources
55
-
56
- - [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)
57
- - [Gitlab Observatoire DPE](https://gitlab.com/observatoire-dpe/observatoire-dpe/-/blob/master/README.md)
58
- - [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=)
59
- - [Légifrance 13/04/2021 valeurs GES](https://www.legifrance.gouv.fr/download/pdf?id=doxMrRr0wbfJVvtWjfDP4gHzzERt1iX0PtobthCE6A0=)
60
- - [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)
61
- - [Valeurs des étiquettes énergétiques](https://docs.google.com/spreadsheets/d/1QVXUOLP8aJukA-PLBGyVB0ZJTWmLEE1WbflXUfsT_jU/edit#gid=0)
62
-
63
- ## Quelques DPE intéressants
64
-
65
- En travaillant sur les DPE je suis tombé sur quelques cas de DPE intéressants
66
-
67
- - `2307E3075089A` chaudiere a condensation + climatiseur
68
- - `2344E2258429L` DPE generé a partir des données immeuble
69
- - `2362E3036179P` poele a charbon
70
- - `2369E2991011Q` 1 radiateur à gaz + fenetres avec masques lointains
71
- - `2387E0402213E` methode_application 'maison_individuelle' mais les portes sont saisie depuis une étude rt2012/rt2020
72
- - `2387E0576340J` 2 gen ch
73
- - `2387E0888781I` inertie lourde + paroi anciennes (tableaux de valeurs différents)
74
- - `2387E1742056P` 2 emetteur ch
75
- - `2387E2058698D` ventil hybride
76
- - `2387E2603968B` inertie lourde + parois ancienne (différentes periode de chauffe)
77
- - `2387E2899635W` 2 installation_ch
78
- - `2387E2923777K` pas d’ECS, pas de portes
79
- - `2387E3074987E` bouclage ECS
80
- - `2387E3092820B` pas de pancher_haut
81
- - `2387E3103131Q` Analysimmo 4.1.1 incohérence ventil calculée comme si presence_joint_menuiserie=1 alors qu’aucune menuiserie n’a de joints
82
- - `2387E3103505A` Analysimmo 4.1.1 incohérence pont thermique, PB considéré pont ITI+ITE ??
83
- - `2187E1039187C` toiture terrasse
84
- - `2387E0291550X` probleme ubat/uph comble amenagés
85
- - `2287E1724516Y` pour un meme generateur, position_volume_chauffe = 0 ou 1 selon si c'est le gen_ecs ou le gen_ch
86
- - `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.
107
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
108
+
109
+ ## Rapports
110
+
111
+ Lister ici les rapports de tests avec stats sur le CORPUS DPE.
112
+
113
+ ## Roadmap
114
+
115
+ - [x] Site Open 3CL
116
+ - [ ] Refacto technique
117
+ - [ ] Rapports de tests
118
+ - [ ] Certification ADEME
119
+ - [ ] Fonctionnalités
120
+ - [ ] DPE à l'immeuble
121
+ - [ ] Photovoltaïque
122
+
123
+ Voir la liste des [issues](https://github.com/Open3CL/engine/issues) pour avoir le détail complet des bugs et fonctionnalités en cours de réalisation.
124
+
125
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
87
126
 
88
127
  ## Contribution
89
128
 
90
129
  Nous accueillons les contributions avec plaisir ! Si vous souhaitez améliorer Open3CL, veuillez :
91
130
 
92
- 1. Forker le dépôt.
93
- 2. Créer une branche pour vos modifications.
94
- 3. Soumettre une pull request avec une description claire des changements apportés.
131
+ - Forker le dépôt.
132
+ - Créer une branche pour vos modifications.
133
+ - Soumettre une pull request avec une description claire des changements apportés.
134
+ - Consultez le fichier [CONTRIBUTING.md](CONTRIBUTING.md) pour plus de détails.
135
+
136
+ ### Meilleurs contributeurs
137
+
138
+ <a href="https://github.com/Open3CL/engine/graphs/contributors">
139
+ <img src="https://contrib.rocks/image?repo=Open3CL/engine" alt="contrib.rocks image" />
140
+ </a>
95
141
 
96
- Consultez le fichier `CONTRIBUTING.md` pour plus de détails.
142
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
97
143
 
98
- ## License
144
+ ## Licence
99
145
 
100
- Ce projet est sous licence [MIT](LICENSE).
146
+ Distribué sous la license `GPL-3.0 license`. Lire le fichier `LICENSE` pour plus d'informations.
147
+
148
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
101
149
 
102
150
  ## Contact
103
151
 
104
- Pour toute question ou suggestion, veuillez contacter l'équipe de développement
152
+ Pour plus d'informations merci de nous contacter à cette adresse : open3cl@redfroggy.fr
153
+
154
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
155
+
156
+ ## Remerciements
157
+
158
+ A compléter
159
+
160
+ <p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
161
+
162
+ [contributors-shield]: https://img.shields.io/github/contributors/Open3CL/engine.svg?style=for-the-badge
163
+ [contributors-url]: https://github.com/Open3CL/engine/graphs/contributors
164
+ [forks-shield]: https://img.shields.io/github/forks/Open3CL/engine.svg?style=for-the-badge
165
+ [forks-url]: https://github.com/Open3CL/network/members
166
+ [stars-shield]: https://img.shields.io/github/stars/Open3CL/engine.svg?style=for-the-badge
167
+ [stars-url]: https://github.com/Open3CL/stargazers
168
+ [issues-shield]: https://img.shields.io/github/issues/Open3CL/engine.svg?style=for-the-badge
169
+ [issues-url]: https://github.com/Open3CL/issues
170
+ [license-shield]: https://img.shields.io/github/license/Open3CL/engine.svg?style=for-the-badge
171
+ [license-url]: https://github.com/Open3CL/blob/master/LICENSE
172
+ [product-screenshot]: images/screenshot.png
173
+ [Javascript]: https://img.shields.io/badge/javascript-000000?style=for-the-badge&logo=javascript&logoColor=white
@@ -8,6 +8,7 @@ export interface Climatisation {
8
8
  export interface ClimatisationDE extends DE {
9
9
  tv_seer_id?: number;
10
10
  nombre_logement_echantillon?: number;
11
+ surface_clim?: number;
11
12
  enum_methode_calcul_conso_id: number;
12
13
  enum_periode_installation_fr_id: number;
13
14
  cle_repartition_clim?: number;
@@ -24,13 +24,13 @@ export class ChTvStore extends TvStore {
24
24
  }
25
25
 
26
26
  /**
27
- * @param tv {string}
27
+ * @param tvType {string}
28
28
  * @returns {any[]}
29
29
  */
30
- #getTypeGenerateurChId(tv) {
30
+ #getTypeGenerateurChId(tvType) {
31
31
  return [
32
32
  ...new Set(
33
- tv[tv].flatMap((v) =>
33
+ tv[tvType].flatMap((v) =>
34
34
  (v.enum_type_generateur_ch_id
35
35
  ? v.enum_type_generateur_ch_id.split('|').map(Number)
36
36
  : []
@@ -1,5 +1,6 @@
1
1
  import { tvs as tv } from '../../../../tv-v2.js';
2
2
  import { TvStore } from './../tv.store.js';
3
+ import { logger } from '../../../../core/util/logger/log-service.js';
3
4
 
4
5
  /**
5
6
  * Accès aux données des tables de valeurs pour le besoin en froid
@@ -35,4 +36,30 @@ export class FrTvStore extends TvStore {
35
36
 
36
37
  return parseFloat(values[classeAltitude][mois][zoneClimatique]);
37
38
  }
39
+
40
+ /**
41
+ * Coefficient d’efficience énergétique
42
+ * @see 10.3 - Les consommations de refroidissement
43
+ *
44
+ * @param zoneClimatiqueId {string}
45
+ * @param periodeInstallationId {number}
46
+ *
47
+ * @return {number|undefined}
48
+ */
49
+ getEer(zoneClimatiqueId, periodeInstallationId) {
50
+ const eer = tv['seer'].find(
51
+ (v) =>
52
+ v.enum_zone_climatique_id.split('|').includes(zoneClimatiqueId) &&
53
+ parseInt(v.enum_periode_installation_fr_id) === periodeInstallationId
54
+ )?.eer;
55
+
56
+ if (!eer) {
57
+ logger.error(
58
+ `Pas de valeur forfaitaire eer pour zoneClimatiqueId:${zoneClimatiqueId}, periodeInstallationId:${periodeInstallationId}`
59
+ );
60
+ return;
61
+ }
62
+
63
+ return parseFloat(eer);
64
+ }
38
65
  }
@@ -49,4 +49,26 @@ describe('Lecture des tables de valeurs', () => {
49
49
  expect(tvStore.getData(type, '400-800m', 'h1a', 'Juin', ilpa)).toBe(expected);
50
50
  });
51
51
  });
52
+
53
+ describe('Lecture des valeurs de coefficient d’efficience énergétique eer', () => {
54
+ test.each([
55
+ {
56
+ zoneClimatiqueId: '2',
57
+ periodeInstallationId: 1,
58
+ expected: 3.6
59
+ },
60
+ {
61
+ zoneClimatiqueId: '8',
62
+ periodeInstallationId: 2,
63
+ expected: 5.415
64
+ }
65
+ ])(`type: $type, ilpa: $ilpa`, ({ zoneClimatiqueId, periodeInstallationId, expected }) => {
66
+ expect(tvStore.getEer(zoneClimatiqueId, periodeInstallationId)).toBe(expected);
67
+ });
68
+
69
+ test('pas de valeur de eer', () => {
70
+ const eer = tvStore.getEer('8', 8);
71
+ expect(eer).toBeUndefined();
72
+ });
73
+ });
52
74
  });
@@ -1,9 +1,9 @@
1
1
  import { inject } from 'dioma';
2
2
  import { ChTvStore } from '../../../dpe/infrastructure/ch/chTv.store.js';
3
- import { TypeGenerateur } from '../../../dpe/domain/models/installation-chauffage.model.js';
4
3
  import { excel_to_js_exec } from '../../../../utils.js';
5
4
  import { TvStore } from '../../../dpe/infrastructure/tv.store.js';
6
5
  import { EmetteurChService } from './emetteur-ch.service.js';
6
+ import { TypeGenerateur } from '../../../dpe/domain/models/type-generateur.model.js';
7
7
 
8
8
  /**
9
9
  * Calcul des données de calcul pour chacun des générateurs
@@ -0,0 +1,26 @@
1
+ import { inject } from 'dioma';
2
+ import { ConsoFroidService } from './froid/conso-froid.service.js';
3
+
4
+ export class ConsoService {
5
+ /**
6
+ * @type {ConsoFroidService}
7
+ */
8
+ #consoFroidService;
9
+
10
+ /**
11
+ * @param consoFroidService {ConsoFroidService}
12
+ */
13
+ constructor(consoFroidService = inject(ConsoFroidService)) {
14
+ this.#consoFroidService = consoFroidService;
15
+ }
16
+
17
+ /**
18
+ * Calcul des consommations
19
+ *
20
+ * @param ctx {Contexte}
21
+ * @param logement {Logement}
22
+ */
23
+ execute(ctx, logement) {
24
+ this.#consoFroidService.execute(ctx, logement);
25
+ }
26
+ }
@@ -0,0 +1,29 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
2
+ import { ConsoFroidService } from './froid/conso-froid.service.js';
3
+ import { ConsoService } from './conso.service.js';
4
+
5
+ /** @type {ConsoService} **/
6
+ let service;
7
+
8
+ /** @type {ConsoFroidService} **/
9
+ let consoFroidService;
10
+
11
+ describe('Calcul des consos du logement', () => {
12
+ beforeEach(() => {
13
+ consoFroidService = new ConsoFroidService();
14
+ service = new ConsoService(consoFroidService);
15
+ });
16
+
17
+ test('Determination des consommmations du logement', () => {
18
+ vi.spyOn(consoFroidService, 'execute').mockReturnThis();
19
+
20
+ /** @type {Contexte} */
21
+ const ctx = { zoneClimatique: { id: 1 }, nadeq: 2.5 };
22
+ /** @type { Logement } **/
23
+ const logement = { enveloppe: {} };
24
+
25
+ service.execute(ctx, logement);
26
+
27
+ expect(consoFroidService.execute).toHaveBeenCalledWith(ctx, logement);
28
+ });
29
+ });
@@ -0,0 +1,94 @@
1
+ import { inject } from 'dioma';
2
+ import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
3
+
4
+ /**
5
+ * Calcul de la consommation en froid
6
+ * Chapitre 10.3 - Les consommations de refroidissement
7
+ *
8
+ * Methode_de_calcul_3CL_DPE_2021 - Page 69
9
+ * Octobre 2021
10
+ * @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
11
+ */
12
+ export class ConsoFroidService {
13
+ /**
14
+ * @type {FrTvStore}
15
+ */
16
+ #frStore;
17
+
18
+ /**
19
+ * @param frStore {FrTvStore}
20
+ */
21
+ constructor(frStore = inject(FrTvStore)) {
22
+ this.#frStore = frStore;
23
+ }
24
+
25
+ /**
26
+ * @param ctx {Contexte}
27
+ * @param logement {Logement}
28
+ * @return {{besoin_fr: number, besoin_fr_depensier: number}}
29
+ */
30
+ execute(ctx, logement) {
31
+ const climatisations = logement.climatisation_collection?.climatisation || [];
32
+
33
+ climatisations.forEach((climatisation) => {
34
+ const consos = this.consoFroid(ctx, logement.sortie.apport_et_besoin, climatisation);
35
+
36
+ climatisation.donnee_intermediaire ??= {};
37
+ climatisation.donnee_intermediaire.besoin_fr = consos.besoin_fr;
38
+ climatisation.donnee_intermediaire.besoin_fr_depensier = consos.besoin_fr_depensier;
39
+ climatisation.donnee_intermediaire.conso_fr = consos.conso_fr;
40
+ climatisation.donnee_intermediaire.conso_fr_depensier = consos.conso_fr_depensier;
41
+ });
42
+ }
43
+
44
+ /**
45
+ * Calcul de la consommation en froid d'un système de refroidissement
46
+ *
47
+ * @param ctx {Contexte}
48
+ * @param apportEtBesoin {ApportEtBesoin}
49
+ * @param climatisation {Climatisation}
50
+ * @returns {{besoin_fr: number, besoin_fr_depensier: number, conso_fr: number, conso_fr_depensier: number}}
51
+ */
52
+ consoFroid(ctx, apportEtBesoin, climatisation) {
53
+ let eer;
54
+
55
+ /** @type {ClimatisationDE} **/
56
+ const climatisationDE = climatisation.donnee_entree;
57
+
58
+ /** @type {ClimatisationDI} **/
59
+ const climatisationDI = climatisation.donnee_intermediaire || {};
60
+
61
+ const ratioSurfaceClimatisation =
62
+ (climatisationDE.surface_clim || ctx.surfaceHabitable) / ctx.surfaceHabitable;
63
+ const besoin_fr = apportEtBesoin.besoin_fr * ratioSurfaceClimatisation;
64
+ const besoin_fr_depensier = apportEtBesoin.besoin_fr_depensier * ratioSurfaceClimatisation;
65
+
66
+ /**
67
+ * Si la méthode de saisie n'est pas "Valeur forfaitaire" mais "caractéristiques saisies"
68
+ * Documentation 3CL : "Pour les installations récentes ou recommandées, les caractéristiques réelles des chaudières présentées sur les bases
69
+ * de données professionnelles peuvent être utilisées."
70
+ *
71
+ * 6 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système thermodynamique : scop/cop/eer
72
+ * 7 - déterminé à partir du rset/rsee( etude rt2012/re2020)
73
+ * 8 - seer saisi pour permettre la saisie de réseau de froid ou de système de climatisations qui ne sont pas éléctriques
74
+ */
75
+ if (
76
+ ![6, 7, 8].includes(parseInt(climatisationDE.enum_methode_saisie_carac_sys_id)) ||
77
+ !climatisationDI.eer
78
+ ) {
79
+ eer = this.#frStore.getEer(
80
+ ctx.zoneClimatique.id,
81
+ parseInt(climatisationDE.enum_periode_installation_fr_id)
82
+ );
83
+ } else {
84
+ eer = climatisationDI.eer;
85
+ }
86
+
87
+ return {
88
+ besoin_fr,
89
+ besoin_fr_depensier,
90
+ conso_fr: (0.9 * besoin_fr) / eer,
91
+ conso_fr_depensier: (0.9 * besoin_fr_depensier) / eer
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,152 @@
1
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
2
+ import { DpeNormalizerService } from '../../../../normalizer/domain/dpe-normalizer.service.js';
3
+ import { ContexteBuilder } from '../../contexte.builder.js';
4
+ import corpus from '../../../../../../test/corpus-sano.json';
5
+ import { getAdemeFileJson } from '../../../../../../test/test-helpers.js';
6
+ import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
7
+ import { ConsoFroidService } from './conso-froid.service.js';
8
+
9
+ /** @type {ConsoFroidService} **/
10
+ let service;
11
+
12
+ /** @type {DpeNormalizerService} **/
13
+ let normalizerService;
14
+
15
+ /** @type {ContexteBuilder} **/
16
+ let contexteBuilder;
17
+
18
+ /** @type {FrTvStore} **/
19
+ let tvStore;
20
+
21
+ describe('Calcul des consos en froid du logement', () => {
22
+ beforeEach(() => {
23
+ tvStore = new FrTvStore();
24
+ service = new ConsoFroidService(tvStore);
25
+ normalizerService = new DpeNormalizerService();
26
+ contexteBuilder = new ContexteBuilder();
27
+ });
28
+
29
+ test.each([
30
+ {
31
+ label: 'Climatisation avec méthode de saisie 6, sans surface clim',
32
+ enumMethodeSaisieCaracSysId: 6,
33
+ eerInitial: 125,
34
+ expected: { conso_fr: 7.2, conso_fr_depensier: 10.8 }
35
+ },
36
+ {
37
+ label: 'Climatisation avec méthode de saisie 7, sans surface clim',
38
+ enumMethodeSaisieCaracSysId: 7,
39
+ eerInitial: 125,
40
+ expected: { conso_fr: 7.2, conso_fr_depensier: 10.8 }
41
+ },
42
+ {
43
+ label: 'Climatisation avec méthode de saisie 8, sans surface clim',
44
+ enumMethodeSaisieCaracSysId: 8,
45
+ eerInitial: 125,
46
+ expected: { conso_fr: 7.2, conso_fr_depensier: 10.8 }
47
+ },
48
+ {
49
+ label: 'Climatisation avec méthode de saisie 6, avec surface clim',
50
+ enumMethodeSaisieCaracSysId: 6,
51
+ eerInitial: 125,
52
+ surfaceClim: 80,
53
+ expected: { conso_fr: 5.76, conso_fr_depensier: 8.64 }
54
+ },
55
+ {
56
+ label: 'Climatisation avec méthode de saisie 7, avec surface clim',
57
+ enumMethodeSaisieCaracSysId: 7,
58
+ eerInitial: 125,
59
+ surfaceClim: 80,
60
+ expected: { conso_fr: 5.76, conso_fr_depensier: 8.64 }
61
+ },
62
+ {
63
+ label: 'Climatisation avec méthode de saisie 8, avec surface clim',
64
+ enumMethodeSaisieCaracSysId: 8,
65
+ eerInitial: 125,
66
+ surfaceClim: 80,
67
+ expected: { conso_fr: 5.76, conso_fr_depensier: 8.64 }
68
+ },
69
+ {
70
+ label: 'Climatisation avec méthode de saisie 5, sans surface clim',
71
+ enumMethodeSaisieCaracSysId: 5,
72
+ eer: 90,
73
+ expected: { conso_fr: 10, conso_fr_depensier: 15 }
74
+ },
75
+ {
76
+ label: 'Climatisation avec méthode de saisie 5, avec surface clim',
77
+ enumMethodeSaisieCaracSysId: 5,
78
+ eer: 90,
79
+ surfaceClim: 80,
80
+ expected: { conso_fr: 8, conso_fr_depensier: 12 }
81
+ }
82
+ ])(
83
+ 'Détermination des consommations des systèmes de refroidissement pour $label',
84
+ ({
85
+ enumMethodeSaisieCaracSysId,
86
+ surfaceClim = undefined,
87
+ eer = undefined,
88
+ eerInitial,
89
+ expected
90
+ }) => {
91
+ vi.spyOn(tvStore, 'getEer').mockReturnValue(eer);
92
+
93
+ /** @type {Contexte} */
94
+ const contexte = {
95
+ zoneClimatique: { id: 1 },
96
+ surfaceHabitable: 100
97
+ };
98
+
99
+ /** @type {Climatisation} */
100
+ const climatisation = {
101
+ donnee_entree: {
102
+ enum_methode_saisie_carac_sys_id: enumMethodeSaisieCaracSysId,
103
+ surface_clim: surfaceClim
104
+ },
105
+ donnee_intermediaire: { eer: eerInitial }
106
+ };
107
+
108
+ /** @type {ApportEtBesoin} */
109
+ const apportEtBesoin = {
110
+ besoin_fr: 1000,
111
+ besoin_fr_depensier: 1500
112
+ };
113
+
114
+ const consoFroid = service.consoFroid(contexte, apportEtBesoin, climatisation);
115
+ expect(consoFroid.conso_fr).toBeCloseTo(expected.conso_fr, 2);
116
+ expect(consoFroid.conso_fr_depensier).toBeCloseTo(expected.conso_fr_depensier, 2);
117
+ }
118
+ );
119
+
120
+ describe("Test d'intégration pour le besoin en froid", () => {
121
+ test.each(corpus)('vérification des sorties besoin_fr et conso_fr pour dpe %s', (ademeId) => {
122
+ /**
123
+ * @type {Dpe}
124
+ */
125
+ let dpeRequest = getAdemeFileJson(ademeId);
126
+ dpeRequest = normalizerService.normalize(dpeRequest);
127
+
128
+ /** @type {Contexte} */
129
+ const ctx = contexteBuilder.fromDpe(dpeRequest);
130
+
131
+ const climatisations = structuredClone(
132
+ dpeRequest.logement.climatisation_collection?.climatisation || []
133
+ );
134
+ service.execute(ctx, dpeRequest.logement);
135
+
136
+ climatisations.forEach((climatisation, i) => {
137
+ console.log('climatisation.donnee_intermediaire.besoin_fr');
138
+ expect(climatisation.donnee_intermediaire.besoin_fr).toBeCloseTo(
139
+ dpeRequest.logement.climatisation_collection.climatisation[i].donnee_intermediaire
140
+ .besoin_fr,
141
+ 2
142
+ );
143
+ console.log(climatisation.donnee_intermediaire.conso_fr);
144
+ expect(climatisation.donnee_intermediaire.conso_fr).toBeCloseTo(
145
+ dpeRequest.logement.climatisation_collection.climatisation[i].donnee_intermediaire
146
+ .conso_fr,
147
+ 2
148
+ );
149
+ });
150
+ });
151
+ });
152
+ });
@@ -3,6 +3,7 @@ import { ContexteBuilder } from './contexte.builder.js';
3
3
  import { DeperditionEnveloppeService } from './enveloppe/deperdition-enveloppe.service.js';
4
4
  import { logger } from '../../../core/util/logger/log-service.js';
5
5
  import { ApportEtBesoinService } from './apport_et_besoin/apport-et-besoin.service.js';
6
+ import { ConsoService } from './conso/conso.service.js';
6
7
 
7
8
  export class EngineService {
8
9
  /**
@@ -15,6 +16,11 @@ export class EngineService {
15
16
  */
16
17
  #apportEtBesoinService;
17
18
 
19
+ /**
20
+ * @type {ConsoService}
21
+ */
22
+ #consoService;
23
+
18
24
  /**
19
25
  * @type {ContexteBuilder}
20
26
  */
@@ -23,15 +29,18 @@ export class EngineService {
23
29
  /**
24
30
  * @param deperditionService {DeperditionEnveloppeService}
25
31
  * @param apportEtBesoinService {ApportEtBesoinService}
32
+ * @param consoService {ConsoService}
26
33
  * @param contextBuilder {ContexteBuilder}
27
34
  */
28
35
  constructor(
29
36
  deperditionService = inject(DeperditionEnveloppeService),
30
37
  apportEtBesoinService = inject(ApportEtBesoinService),
38
+ consoService = inject(ConsoService),
31
39
  contextBuilder = inject(ContexteBuilder)
32
40
  ) {
33
41
  this.#deperditionService = deperditionService;
34
42
  this.#apportEtBesoinService = apportEtBesoinService;
43
+ this.#consoService = consoService;
35
44
  this.#contextBuilder = contextBuilder;
36
45
  }
37
46
 
@@ -98,6 +107,7 @@ export class EngineService {
98
107
  // Calcul des consommations chauffage
99
108
 
100
109
  // Calcul des consommations de froid
110
+ this.#consoService.execute(ctx, proceededDpe.logement);
101
111
 
102
112
  // Calcul des consommations ECS
103
113
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open3cl/engine",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "Open Source 3CL-DPE engine",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -14,6 +14,14 @@
14
14
  "scripts": {
15
15
  "test": "vitest run",
16
16
  "test:ci": "vitest run --coverage",
17
+ "test:corpus": "node test/corpus/run_corpus_checks.js",
18
+ "test:corpus:bench:5": "npm run test:corpus -- threshold=5 && npm run test:corpus -- compatibility threshold=5",
19
+ "test:corpus:bench:6": "npm run test:corpus -- threshold=6 && npm run test:corpus -- compatibility threshold=6",
20
+ "test:corpus:bench:7": "npm run test:corpus -- threshold=7 && npm run test:corpus -- compatibility threshold=7",
21
+ "test:corpus:bench:8": "npm run test:corpus -- threshold=8 && npm run test:corpus -- compatibility threshold=8",
22
+ "test:corpus:bench:9": "npm run test:corpus -- threshold=9 && npm run test:corpus -- compatibility threshold=9",
23
+ "test:corpus:bench:10": "npm run test:corpus -- threshold=10 && npm run test:corpus -- compatibility threshold=10",
24
+ "test:corpus:bench": "npm run test:corpus:bench:5 && npm run test:corpus:bench:6 && npm run test:corpus:bench:7 && npm run test:corpus:bench:8 && npm run test:corpus:bench:9 && npm run test:corpus:bench:10",
17
25
  "test:benchmark": "node inspect test/run_benchmark.js",
18
26
  "qa:lint": "eslint .",
19
27
  "qa:lint:fix": "npm run qa:lint -- --fix",
@@ -35,7 +43,7 @@
35
43
  "dependencies": {
36
44
  "dioma": "^0.4.6",
37
45
  "fast-xml-parser": "^4.5.0",
38
- "lodash": "^4.17.21",
46
+ "lodash-es": "^4.17.21",
39
47
  "winston": "3.13.0"
40
48
  },
41
49
  "devDependencies": {
@@ -55,6 +63,7 @@
55
63
  "eslint-plugin-import": "^2.29.1",
56
64
  "eslint-plugin-n": "^16.6.2",
57
65
  "eslint-plugin-promise": "^6.1.1",
66
+ "fast-csv": "^5.0.2",
58
67
  "husky": "^9.0.11",
59
68
  "jscpd": "^3.5.10",
60
69
  "prettier": "^3.2.5",