@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 +8 -1
- package/README.md +128 -59
- package/features/dpe/domain/models/climatisation.model.ts +1 -0
- package/features/dpe/infrastructure/ch/chTv.store.js +3 -3
- package/features/dpe/infrastructure/froid/frTv.store.js +27 -0
- package/features/dpe/infrastructure/froid/frTv.store.spec.js +22 -0
- package/features/engine/domain/ch/generateur-ch.service.js +1 -1
- package/features/engine/domain/conso/conso.service.js +26 -0
- package/features/engine/domain/conso/conso.service.spec.js +29 -0
- package/features/engine/domain/conso/froid/conso-froid.service.js +94 -0
- package/features/engine/domain/conso/froid/conso-froid.service.spec.js +152 -0
- package/features/engine/domain/engine.service.js +10 -0
- package/package.json +11 -2
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
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
·
|
|
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
|
-
|
|
70
|
+
### Documentation
|
|
12
71
|
|
|
13
|
-
|
|
14
|
-
npm install @open3cl/engine
|
|
15
|
-
```
|
|
72
|
+
Lien à faire vers les wiki
|
|
16
73
|
|
|
17
|
-
|
|
74
|
+
<p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
|
|
18
75
|
|
|
19
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
- [
|
|
59
|
-
- [
|
|
60
|
-
- [
|
|
61
|
-
- [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
142
|
+
<p align="right">(<a href="#readme-top">Retour sommaire</a>)</p>
|
|
97
143
|
|
|
98
|
-
##
|
|
144
|
+
## Licence
|
|
99
145
|
|
|
100
|
-
|
|
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
|
|
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
|
|
27
|
+
* @param tvType {string}
|
|
28
28
|
* @returns {any[]}
|
|
29
29
|
*/
|
|
30
|
-
#getTypeGenerateurChId(
|
|
30
|
+
#getTypeGenerateurChId(tvType) {
|
|
31
31
|
return [
|
|
32
32
|
...new Set(
|
|
33
|
-
tv[
|
|
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.
|
|
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",
|