@open3cl/engine 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/features/dpe/domain/models/installation-ecs.model.ts +15 -2
- package/features/dpe/domain/models/type-habitation.model.js +1 -0
- package/features/dpe/domain/models/type-stockage.model.js +8 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.js +65 -0
- package/features/dpe/infrastructure/ecs/ecsTv.store.spec.js +69 -0
- package/features/dpe/infrastructure/{baieVitreeTv.store.js → enveloppe/baieVitreeTv.store.js} +5 -5
- package/features/dpe/infrastructure/{pontThermiqueTv.store.js → enveloppe/pontThermiqueTv.store.js} +3 -3
- package/features/dpe/infrastructure/froid/frTv.store.js +36 -0
- package/features/dpe/infrastructure/froid/frTv.store.spec.js +52 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.js +100 -0
- package/features/engine/domain/apport_et_besoin/apport-et-besoin.service.spec.js +106 -0
- package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.js +134 -0
- package/features/engine/domain/apport_et_besoin/apport_gratuit/apport-gratuit.service.spec.js +167 -0
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.js +58 -0
- package/features/engine/domain/apport_et_besoin/ecs/besoin-ecs.service.spec.js +67 -0
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.js +123 -0
- package/features/engine/domain/apport_et_besoin/ecs/perte-ecs-recup.service.spec.js +205 -0
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.js +131 -0
- package/features/engine/domain/apport_et_besoin/froid/besoin-froid.service.spec.js +229 -0
- package/features/engine/domain/{logement → apport_et_besoin}/surface-sud-equivalente.service.js +9 -10
- package/features/engine/domain/{logement → apport_et_besoin}/surface-sud-equivalente.service.spec.js +63 -43
- package/features/engine/domain/contexte.builder.js +53 -6
- package/features/engine/domain/contexte.builder.spec.js +59 -3
- package/features/engine/domain/ecs/generateur-ecs.service.js +106 -0
- package/features/engine/domain/ecs/generateur-ecs.service.spec.js +136 -0
- package/features/engine/domain/ecs/installation-ecs.service.js +156 -0
- package/features/engine/domain/ecs/installation-ecs.service.spec.js +284 -0
- package/features/engine/domain/engine.service.js +10 -13
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.js +1 -1
- package/features/engine/domain/enveloppe/baie_vitree/deperdition-baie-vitree.service.spec.js +1 -1
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.js +1 -1
- package/features/engine/domain/enveloppe/espace_tampon/espace-tampon.service.spec.js +1 -1
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.js +1 -1
- package/features/engine/domain/enveloppe/pont_thermique/deperdition-pont-thermique.service.spec.js +1 -1
- package/features/engine/domain/logement/nadeq.service.js +8 -7
- package/features/engine/domain/logement/nadeq.service.spec.js +6 -16
- package/features/engine/domain/models/contexte.model.ts +9 -0
- package/package.json +1 -1
- /package/features/dpe/infrastructure/{baieVitreeTv.store.spec.js → enveloppe/baieVitreeTv.store.spec.js} +0 -0
- /package/features/dpe/infrastructure/{pontThermiqueTv.store.spec.js → enveloppe/pontThermiqueTv.store.spec.js} +0 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { mois_liste } from '../../../../../utils.js';
|
|
2
|
+
import { inject } from 'dioma';
|
|
3
|
+
import { FrTvStore } from '../../../../dpe/infrastructure/froid/frTv.store.js';
|
|
4
|
+
import { ApportGratuitService } from '../apport_gratuit/apport-gratuit.service.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Calcul du besoin en froid
|
|
8
|
+
* Chapitre 10.2 Calcul du besoin mensuel de froid
|
|
9
|
+
*
|
|
10
|
+
* Methode_de_calcul_3CL_DPE_2021 - Page 68
|
|
11
|
+
* Octobre 2021
|
|
12
|
+
* @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
|
|
13
|
+
*/
|
|
14
|
+
export class BesoinFroidService {
|
|
15
|
+
/**
|
|
16
|
+
* @type {ApportGratuitService}
|
|
17
|
+
*/
|
|
18
|
+
#apportGratuitService;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @type {FrTvStore}
|
|
22
|
+
*/
|
|
23
|
+
#tvStore;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param tvStore {FrTvStore}
|
|
27
|
+
* @param apportGratuitService {ApportGratuitService}
|
|
28
|
+
*/
|
|
29
|
+
constructor(tvStore = inject(FrTvStore), apportGratuitService = inject(ApportGratuitService)) {
|
|
30
|
+
this.#tvStore = tvStore;
|
|
31
|
+
this.#apportGratuitService = apportGratuitService;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param ctx {Contexte}
|
|
36
|
+
* @param logement {Logement}
|
|
37
|
+
* @return {{besoin_fr: number, besoin_fr_depensier: number}}
|
|
38
|
+
*/
|
|
39
|
+
execute(ctx, logement) {
|
|
40
|
+
const clim = logement.climatisation_collection?.climatisation || [];
|
|
41
|
+
if (clim.length === 0) {
|
|
42
|
+
return { besoin_fr: 0, besoin_fr_depensier: 0 };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return mois_liste.reduce(
|
|
46
|
+
(acc, mois) => {
|
|
47
|
+
acc.besoin_fr += this.besoinFrMois(ctx, logement, mois, false);
|
|
48
|
+
acc.besoin_fr_depensier += this.besoinFrMois(ctx, logement, mois, true);
|
|
49
|
+
return acc;
|
|
50
|
+
},
|
|
51
|
+
{ besoin_fr: 0, besoin_fr_depensier: 0 }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Calcul du besoin en froid pour un mois donné
|
|
57
|
+
*
|
|
58
|
+
* @param ctx {Contexte}
|
|
59
|
+
* @param logement {Logement}
|
|
60
|
+
* @param mois {string}
|
|
61
|
+
* @param depensier {boolean}
|
|
62
|
+
* @returns {number}
|
|
63
|
+
*/
|
|
64
|
+
besoinFrMois(ctx, logement, mois, depensier) {
|
|
65
|
+
const nref = this.#tvStore.getData(
|
|
66
|
+
depensier ? 'nref26' : 'nref28',
|
|
67
|
+
ctx.altitude.value,
|
|
68
|
+
ctx.zoneClimatique.value,
|
|
69
|
+
mois
|
|
70
|
+
);
|
|
71
|
+
if (nref === 0) return 0;
|
|
72
|
+
|
|
73
|
+
const eFr = this.#tvStore.getData(
|
|
74
|
+
depensier ? 'e_fr_26' : 'e_fr_28',
|
|
75
|
+
ctx.altitude.value,
|
|
76
|
+
ctx.zoneClimatique.value,
|
|
77
|
+
mois
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// Température extérieure moyenne sur le mois j pendant les périodes de climatisation (°C)
|
|
81
|
+
const tempExtMoyClim = this.#tvStore.getData(
|
|
82
|
+
depensier ? 'textmoy_clim_26' : 'textmoy_clim_28',
|
|
83
|
+
ctx.altitude.value,
|
|
84
|
+
ctx.zoneClimatique.value,
|
|
85
|
+
mois
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Température de consigne en froid (°C)
|
|
89
|
+
const temperatureInterieure = depensier ? 26 : 28;
|
|
90
|
+
|
|
91
|
+
const aijFr = this.#apportGratuitService.apportInterneMois(ctx, nref);
|
|
92
|
+
const asjFr = this.#apportGratuitService.apportSolaireMois(ctx, logement.enveloppe, mois, eFr);
|
|
93
|
+
|
|
94
|
+
// Transfert thermique à travers l’enveloppe et le renouvellement d’air (W/K). Le GV prend en compte les
|
|
95
|
+
// échanges de chaleur par le renouvellement d‘air. Ces échanges sont calculés sur la période de refroidissement
|
|
96
|
+
// de la même façon que pour la période de chauffage
|
|
97
|
+
const GV = logement.sortie?.deperdition?.deperdition_enveloppe;
|
|
98
|
+
|
|
99
|
+
// Ratio de bilan thermique
|
|
100
|
+
const Rbth = (aijFr + asjFr) / (GV * (tempExtMoyClim - temperatureInterieure) * nref);
|
|
101
|
+
|
|
102
|
+
if (Rbth < 1 / 2) return 0;
|
|
103
|
+
|
|
104
|
+
// Constante de temps de la zone pour le refroidissement
|
|
105
|
+
const t = (this.#cin(ctx.inertie.id) * ctx.surfaceHabitable) / (3600 * GV);
|
|
106
|
+
const a = 1 + t / 15;
|
|
107
|
+
|
|
108
|
+
// Facteur d'utilisation des apports sur le mois
|
|
109
|
+
let fut = Rbth === 1 ? a / (a + 1) : (1 - Rbth ** -a) / (1 - Rbth ** (-a - 1));
|
|
110
|
+
return (
|
|
111
|
+
(aijFr + asjFr) / 1000 - ((fut * GV) / 1000) * (temperatureInterieure - tempExtMoyClim) * nref
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Capacité thermique intérieure efficace de la zone (J/K)
|
|
117
|
+
* @param inertie
|
|
118
|
+
* @returns {number}
|
|
119
|
+
*/
|
|
120
|
+
#cin(inertie) {
|
|
121
|
+
switch (inertie) {
|
|
122
|
+
case 1:
|
|
123
|
+
case 2:
|
|
124
|
+
return 260000;
|
|
125
|
+
case 3:
|
|
126
|
+
return 165000;
|
|
127
|
+
case 4:
|
|
128
|
+
return 110000;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
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 { ApportGratuitService } from '../apport_gratuit/apport-gratuit.service.js';
|
|
8
|
+
import { BesoinFroidService } from './besoin-froid.service.js';
|
|
9
|
+
|
|
10
|
+
/** @type {ApportGratuitService} **/
|
|
11
|
+
let apportGratuitService;
|
|
12
|
+
|
|
13
|
+
/** @type {BesoinFroidService} **/
|
|
14
|
+
let service;
|
|
15
|
+
|
|
16
|
+
/** @type {DpeNormalizerService} **/
|
|
17
|
+
let normalizerService;
|
|
18
|
+
|
|
19
|
+
/** @type {ContexteBuilder} **/
|
|
20
|
+
let contexteBuilder;
|
|
21
|
+
|
|
22
|
+
/** @type {FrTvStore} **/
|
|
23
|
+
let tvStore;
|
|
24
|
+
|
|
25
|
+
describe('Calcul des besoins en froid du logement', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
tvStore = new FrTvStore();
|
|
28
|
+
apportGratuitService = new ApportGratuitService();
|
|
29
|
+
service = new BesoinFroidService(tvStore, apportGratuitService);
|
|
30
|
+
normalizerService = new DpeNormalizerService();
|
|
31
|
+
contexteBuilder = new ContexteBuilder();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('Besoins en froid à 0 si aucune climatisation dans le logement', () => {
|
|
35
|
+
vi.spyOn(tvStore, 'getData').mockReturnValue(10);
|
|
36
|
+
|
|
37
|
+
/** @type {Contexte} */
|
|
38
|
+
const ctx = { zoneClimatique: { id: 1 } };
|
|
39
|
+
expect(service.execute(ctx, {})).toStrictEqual({ besoin_fr: 0, besoin_fr_depensier: 0 });
|
|
40
|
+
expect(service.execute(ctx, { enveloppe: {} })).toStrictEqual({
|
|
41
|
+
besoin_fr: 0,
|
|
42
|
+
besoin_fr_depensier: 0
|
|
43
|
+
});
|
|
44
|
+
expect(service.execute(ctx, { climatisation_collection: {} })).toStrictEqual({
|
|
45
|
+
besoin_fr: 0,
|
|
46
|
+
besoin_fr_depensier: 0
|
|
47
|
+
});
|
|
48
|
+
expect(service.execute(ctx, { climatisation_collection: { climatisation: [] } })).toStrictEqual(
|
|
49
|
+
{ besoin_fr: 0, besoin_fr_depensier: 0 }
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
expect(tvStore.getData).not.toHaveBeenCalled();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('Determination du besoin en froid pour un mois donné', () => {
|
|
56
|
+
test.each([
|
|
57
|
+
{
|
|
58
|
+
data: 0,
|
|
59
|
+
aijFr: 1,
|
|
60
|
+
asjFr: 0.2,
|
|
61
|
+
inertie: 4,
|
|
62
|
+
depensier: false,
|
|
63
|
+
expected: 0
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
data: 0,
|
|
67
|
+
aijFr: 1,
|
|
68
|
+
asjFr: 0.2,
|
|
69
|
+
inertie: 4,
|
|
70
|
+
depensier: true,
|
|
71
|
+
expected: 0
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
data: 58,
|
|
75
|
+
aijFr: 1,
|
|
76
|
+
asjFr: 0.2,
|
|
77
|
+
inertie: 4,
|
|
78
|
+
depensier: false,
|
|
79
|
+
expected: 0
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
data: 58,
|
|
83
|
+
aijFr: 1,
|
|
84
|
+
asjFr: 0.2,
|
|
85
|
+
inertie: 4,
|
|
86
|
+
depensier: true,
|
|
87
|
+
expected: 0
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
data: 30,
|
|
91
|
+
aijFr: 1000,
|
|
92
|
+
asjFr: 2580,
|
|
93
|
+
inertie: 4,
|
|
94
|
+
depensier: false,
|
|
95
|
+
expected: 6.25
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
data: 30,
|
|
99
|
+
aijFr: 1000,
|
|
100
|
+
asjFr: 2580,
|
|
101
|
+
inertie: 4,
|
|
102
|
+
depensier: true,
|
|
103
|
+
expected: 0
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
data: 30,
|
|
107
|
+
aijFr: 1500,
|
|
108
|
+
asjFr: 5580,
|
|
109
|
+
inertie: 4,
|
|
110
|
+
depensier: true,
|
|
111
|
+
expected: 12.38
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
data: 30,
|
|
115
|
+
aijFr: 10000,
|
|
116
|
+
asjFr: 2000,
|
|
117
|
+
inertie: 4,
|
|
118
|
+
depensier: false,
|
|
119
|
+
expected: 16.72
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
data: 30,
|
|
123
|
+
aijFr: 10000,
|
|
124
|
+
asjFr: 2000,
|
|
125
|
+
inertie: 1,
|
|
126
|
+
depensier: true,
|
|
127
|
+
expected: 20.25
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
data: 30,
|
|
131
|
+
aijFr: 10000,
|
|
132
|
+
asjFr: 2000,
|
|
133
|
+
inertie: 2,
|
|
134
|
+
depensier: true,
|
|
135
|
+
expected: 20.25
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
data: 30,
|
|
139
|
+
aijFr: 10000,
|
|
140
|
+
asjFr: 2000,
|
|
141
|
+
inertie: 3,
|
|
142
|
+
depensier: true,
|
|
143
|
+
expected: 19.66
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
data: 30,
|
|
147
|
+
aijFr: 10000,
|
|
148
|
+
asjFr: 2000,
|
|
149
|
+
inertie: 4,
|
|
150
|
+
depensier: true,
|
|
151
|
+
expected: 19.22
|
|
152
|
+
}
|
|
153
|
+
])(
|
|
154
|
+
'nref: $data, eFr: $data, tempExtMoyClim: $data, aijFr: $aijFr, asjFr: $asjFr,' +
|
|
155
|
+
'inertie: $inertie, depensier: $depensier',
|
|
156
|
+
({ data, aijFr, asjFr, inertie, depensier, expected }) => {
|
|
157
|
+
vi.spyOn(tvStore, 'getData').mockReturnValue(data);
|
|
158
|
+
vi.spyOn(apportGratuitService, 'apportInterneMois').mockReturnValue(aijFr);
|
|
159
|
+
vi.spyOn(apportGratuitService, 'apportSolaireMois').mockReturnValue(asjFr);
|
|
160
|
+
|
|
161
|
+
/** @type {Logement} **/
|
|
162
|
+
const logement = {
|
|
163
|
+
enveloppe: {},
|
|
164
|
+
sortie: { deperdition: { deperdition_enveloppe: 100 } }
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/** @type {Contexte} */
|
|
168
|
+
const ctx = {
|
|
169
|
+
altitude: { value: '400-800m' },
|
|
170
|
+
zoneClimatique: { value: 'h1a' },
|
|
171
|
+
inertie: { id: inertie },
|
|
172
|
+
surfaceHabitable: 25
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const ssd = service.besoinFrMois(ctx, logement, 'Janvier', depensier);
|
|
176
|
+
|
|
177
|
+
expect(tvStore.getData).toHaveBeenCalledWith(
|
|
178
|
+
depensier ? 'nref26' : 'nref28',
|
|
179
|
+
'400-800m',
|
|
180
|
+
'h1a',
|
|
181
|
+
'Janvier'
|
|
182
|
+
);
|
|
183
|
+
if (data > 0) {
|
|
184
|
+
expect(tvStore.getData).toHaveBeenCalledWith(
|
|
185
|
+
depensier ? 'e_fr_26' : 'e_fr_28',
|
|
186
|
+
'400-800m',
|
|
187
|
+
'h1a',
|
|
188
|
+
'Janvier'
|
|
189
|
+
);
|
|
190
|
+
expect(tvStore.getData).toHaveBeenCalledWith(
|
|
191
|
+
depensier ? 'textmoy_clim_26' : 'textmoy_clim_28',
|
|
192
|
+
'400-800m',
|
|
193
|
+
'h1a',
|
|
194
|
+
'Janvier'
|
|
195
|
+
);
|
|
196
|
+
expect(apportGratuitService.apportInterneMois).toHaveBeenCalledWith(ctx, data);
|
|
197
|
+
expect(apportGratuitService.apportSolaireMois).toHaveBeenCalledWith(
|
|
198
|
+
ctx,
|
|
199
|
+
{},
|
|
200
|
+
'Janvier',
|
|
201
|
+
data
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
expect(ssd).toBeCloseTo(expected, 2);
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("Test d'intégration pour le besoin en froid", () => {
|
|
211
|
+
test.each(corpus)('vérification des sorties besoin_fr pour dpe %s', (ademeId) => {
|
|
212
|
+
/**
|
|
213
|
+
* @type {Dpe}
|
|
214
|
+
*/
|
|
215
|
+
let dpeRequest = getAdemeFileJson(ademeId);
|
|
216
|
+
dpeRequest = normalizerService.normalize(dpeRequest);
|
|
217
|
+
|
|
218
|
+
/** @type {Contexte} */
|
|
219
|
+
const ctx = contexteBuilder.fromDpe(dpeRequest);
|
|
220
|
+
|
|
221
|
+
const ecs = service.execute(ctx, dpeRequest.logement);
|
|
222
|
+
expect(ecs.besoin_fr).toBeCloseTo(dpeRequest.logement.sortie.apport_et_besoin.besoin_fr, 2);
|
|
223
|
+
expect(ecs.besoin_fr_depensier).toBeCloseTo(
|
|
224
|
+
dpeRequest.logement.sortie.apport_et_besoin.besoin_fr_depensier,
|
|
225
|
+
2
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
});
|
package/features/engine/domain/{logement → apport_et_besoin}/surface-sud-equivalente.service.js
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { mois_liste } from '../../../../utils.js';
|
|
2
2
|
import { inject } from 'dioma';
|
|
3
|
-
import { BaieVitreeTvStore } from '../../../dpe/infrastructure/baieVitreeTv.store.js';
|
|
3
|
+
import { BaieVitreeTvStore } from '../../../dpe/infrastructure/enveloppe/baieVitreeTv.store.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Calcul
|
|
6
|
+
* Calcul de la surface sud équivalente du logement
|
|
7
7
|
* Chapitre 6.2 Détermination de la surface Sud équivalente
|
|
8
8
|
*
|
|
9
9
|
* Methode_de_calcul_3CL_DPE_2021 - Page 45
|
|
@@ -29,22 +29,21 @@ export class SurfaceSudEquivalenteService {
|
|
|
29
29
|
* @return {number}
|
|
30
30
|
*/
|
|
31
31
|
execute(ctx, enveloppe) {
|
|
32
|
-
|
|
33
|
-
const ets = enveloppe.ets_collection?.ets || [];
|
|
34
|
-
|
|
35
|
-
return mois_liste.reduce((acc, mois) => acc + this.ssdMois(ctx, baiesVitrees, ets, mois), 0);
|
|
32
|
+
return mois_liste.reduce((acc, mois) => acc + this.ssdMois(ctx, enveloppe, mois), 0);
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
/**
|
|
39
|
-
* Calcul de la surface sud du logement pour un mois donné
|
|
36
|
+
* Calcul de la surface sud équivalente du logement pour un mois donné
|
|
40
37
|
*
|
|
41
38
|
* @param ctx {Contexte}
|
|
42
|
-
* @param
|
|
43
|
-
* @param ets {Ets}
|
|
39
|
+
* @param enveloppe {Enveloppe}
|
|
44
40
|
* @param mois {string}
|
|
45
41
|
* @returns {number}
|
|
46
42
|
*/
|
|
47
|
-
ssdMois(ctx,
|
|
43
|
+
ssdMois(ctx, enveloppe, mois) {
|
|
44
|
+
const baiesVitrees = enveloppe.baie_vitree_collection?.baie_vitree || [];
|
|
45
|
+
let ets = enveloppe.ets_collection?.ets || [];
|
|
46
|
+
|
|
48
47
|
let SseVerandaj = 0;
|
|
49
48
|
|
|
50
49
|
/**
|
package/features/engine/domain/{logement → apport_et_besoin}/surface-sud-equivalente.service.spec.js
RENAMED
|
@@ -4,7 +4,7 @@ import { DpeNormalizerService } from '../../../normalizer/domain/dpe-normalizer.
|
|
|
4
4
|
import { ContexteBuilder } from '../contexte.builder.js';
|
|
5
5
|
import { SurfaceSudEquivalenteService } from './surface-sud-equivalente.service.js';
|
|
6
6
|
import { getAdemeFileJson } from '../../../../../test/test-helpers.js';
|
|
7
|
-
import { BaieVitreeTvStore } from '../../../dpe/infrastructure/baieVitreeTv.store.js';
|
|
7
|
+
import { BaieVitreeTvStore } from '../../../dpe/infrastructure/enveloppe/baieVitreeTv.store.js';
|
|
8
8
|
|
|
9
9
|
/** @type {SurfaceSudEquivalenteService} **/
|
|
10
10
|
let service;
|
|
@@ -18,7 +18,7 @@ let contexteBuilder;
|
|
|
18
18
|
/** @type {BaieVitreeTvStore} **/
|
|
19
19
|
let tvStore;
|
|
20
20
|
|
|
21
|
-
describe('Calcul de
|
|
21
|
+
describe('Calcul de la surface sud équivalente du logement', () => {
|
|
22
22
|
beforeEach(() => {
|
|
23
23
|
tvStore = new BaieVitreeTvStore();
|
|
24
24
|
service = new SurfaceSudEquivalenteService(tvStore);
|
|
@@ -118,12 +118,17 @@ describe('Calcul de déperdition des portes', () => {
|
|
|
118
118
|
test("Aucune pour les baies vitrées qui ne donnent pas sur l'extérieur", () => {
|
|
119
119
|
expect(service.execute({}, [])).toBe(0);
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
/** @type {Enveloppe} */
|
|
122
|
+
const enveloppe = {
|
|
123
|
+
baie_vitree_collection: {
|
|
124
|
+
baie_vitree: [
|
|
125
|
+
{
|
|
126
|
+
donnee_entree: { enum_type_adjacence_id: 18 }
|
|
127
|
+
}
|
|
128
|
+
]
|
|
124
129
|
}
|
|
125
|
-
|
|
126
|
-
expect(service.ssdMois({},
|
|
130
|
+
};
|
|
131
|
+
expect(service.ssdMois({}, enveloppe, 'Janvier')).toBe(0);
|
|
127
132
|
});
|
|
128
133
|
|
|
129
134
|
test("Baies vitrées donnant sur l'extérieur", () => {
|
|
@@ -131,17 +136,23 @@ describe('Calcul de déperdition des portes', () => {
|
|
|
131
136
|
|
|
132
137
|
/** @type {Contexte} */
|
|
133
138
|
const ctx = { zoneClimatique: { id: 1 } };
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
|
|
140
|
+
/** @type {Enveloppe} */
|
|
141
|
+
const enveloppe = {
|
|
142
|
+
baie_vitree_collection: {
|
|
143
|
+
baie_vitree: [
|
|
144
|
+
{
|
|
145
|
+
donnee_entree: {
|
|
146
|
+
enum_type_adjacence_id: 1,
|
|
147
|
+
enum_orientation_id: 2,
|
|
148
|
+
surface_totale_baie: 10
|
|
149
|
+
},
|
|
150
|
+
donnee_intermediaire: { sw: 1 }
|
|
151
|
+
}
|
|
152
|
+
]
|
|
142
153
|
}
|
|
143
|
-
|
|
144
|
-
expect(service.ssdMois(ctx,
|
|
154
|
+
};
|
|
155
|
+
expect(service.ssdMois(ctx, enveloppe, 'Janvier')).toBe(5);
|
|
145
156
|
expect(tvStore.getCoefficientBaieVitree).toHaveBeenCalledWith(2, 3, 1, 'Janvier');
|
|
146
157
|
});
|
|
147
158
|
|
|
@@ -150,37 +161,46 @@ describe('Calcul de déperdition des portes', () => {
|
|
|
150
161
|
|
|
151
162
|
/** @type {Contexte} */
|
|
152
163
|
const ctx = { zoneClimatique: { id: 1 } };
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
|
|
165
|
+
/** @type {Enveloppe} */
|
|
166
|
+
const enveloppe = {
|
|
167
|
+
baie_vitree_collection: {
|
|
168
|
+
baie_vitree: [
|
|
169
|
+
{
|
|
170
|
+
donnee_entree: {
|
|
171
|
+
enum_type_adjacence_id: 10,
|
|
172
|
+
enum_orientation_id: 2,
|
|
173
|
+
surface_totale_baie: 10
|
|
174
|
+
},
|
|
175
|
+
donnee_intermediaire: { sw: 1 }
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
donnee_entree: {
|
|
179
|
+
enum_type_adjacence_id: 1,
|
|
180
|
+
enum_orientation_id: 2,
|
|
181
|
+
surface_totale_baie: 10
|
|
182
|
+
},
|
|
183
|
+
donnee_intermediaire: { sw: 1 }
|
|
184
|
+
}
|
|
185
|
+
]
|
|
161
186
|
},
|
|
162
|
-
{
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
baie_ets_collection: {
|
|
174
|
-
baie_ets: {
|
|
175
|
-
donnee_entree: {
|
|
176
|
-
enum_inclinaison_vitrage_id: 3,
|
|
177
|
-
enum_orientation_id: 1,
|
|
178
|
-
surface_totale_baie: 7
|
|
187
|
+
ets_collection: {
|
|
188
|
+
ets: {
|
|
189
|
+
donnee_intermediaire: { bver: 0.6, coef_transparence_ets: 0.4 },
|
|
190
|
+
baie_ets_collection: {
|
|
191
|
+
baie_ets: {
|
|
192
|
+
donnee_entree: {
|
|
193
|
+
enum_inclinaison_vitrage_id: 3,
|
|
194
|
+
enum_orientation_id: 1,
|
|
195
|
+
surface_totale_baie: 7
|
|
196
|
+
}
|
|
197
|
+
}
|
|
179
198
|
}
|
|
180
199
|
}
|
|
181
200
|
}
|
|
182
201
|
};
|
|
183
|
-
|
|
202
|
+
|
|
203
|
+
expect(service.ssdMois(ctx, enveloppe, 'Janvier')).toBe(6.5224);
|
|
184
204
|
expect(tvStore.getCoefficientBaieVitree).toHaveBeenCalledWith(2, 3, 1, 'Janvier');
|
|
185
205
|
expect(tvStore.getCoefficientBaieVitree).toHaveBeenCalledWith(1, 3, 1, 'Janvier');
|
|
186
206
|
});
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { TypeDpe, TypeHabitation } from '../../dpe/domain/models/type-habitation.model.js';
|
|
2
2
|
import enums from '../../../enums.js';
|
|
3
|
+
import { NadeqService } from './logement/nadeq.service.js';
|
|
4
|
+
import { inject } from 'dioma';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Génère un contexte du logement à étudier avec des données persistées durant l'analyse
|
|
6
8
|
*/
|
|
7
9
|
export class ContexteBuilder {
|
|
8
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @type {NadeqService}
|
|
12
|
+
*/
|
|
13
|
+
#nadeqService;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param nadeqService {NadeqService}
|
|
17
|
+
*/
|
|
18
|
+
constructor(nadeqService = inject(NadeqService)) {
|
|
19
|
+
this.#nadeqService = nadeqService;
|
|
20
|
+
}
|
|
9
21
|
|
|
10
22
|
/**
|
|
11
23
|
* @param dpe {Dpe}
|
|
@@ -14,22 +26,40 @@ export class ContexteBuilder {
|
|
|
14
26
|
fromDpe(dpe) {
|
|
15
27
|
const caracteristiqueGenerale = dpe.logement.caracteristique_generale;
|
|
16
28
|
|
|
29
|
+
const typeDpe = this.#getTypeDpe(caracteristiqueGenerale);
|
|
30
|
+
const surfaceHabitable = this.#getSurfaceHabitable(caracteristiqueGenerale);
|
|
31
|
+
const inertieId = parseInt(dpe.logement.enveloppe?.inertie?.enum_classe_inertie_id);
|
|
32
|
+
|
|
17
33
|
return {
|
|
18
34
|
zoneClimatique: this.#zoneClimatique(dpe),
|
|
35
|
+
altitude: this.#altitude(dpe),
|
|
19
36
|
typeHabitation: this.#getTypeHabitation(caracteristiqueGenerale),
|
|
20
|
-
typeDpe:
|
|
37
|
+
typeDpe: typeDpe,
|
|
21
38
|
enumPeriodeConstructionId: caracteristiqueGenerale.enum_periode_construction_id?.toString(),
|
|
22
39
|
effetJoule: this.#hasEffetJoule(dpe),
|
|
23
|
-
surfaceHabitable:
|
|
40
|
+
surfaceHabitable: surfaceHabitable,
|
|
24
41
|
hauteurSousPlafond: caracteristiqueGenerale.hsp,
|
|
25
|
-
nombreAppartement: caracteristiqueGenerale.nombre_appartement
|
|
42
|
+
nombreAppartement: caracteristiqueGenerale.nombre_appartement,
|
|
43
|
+
nadeq: this.#nadeqService.execute(
|
|
44
|
+
typeDpe,
|
|
45
|
+
surfaceHabitable,
|
|
46
|
+
caracteristiqueGenerale.nombre_appartement
|
|
47
|
+
),
|
|
48
|
+
inertie: {
|
|
49
|
+
id: inertieId,
|
|
50
|
+
ilpa:
|
|
51
|
+
parseInt(dpe.logement.meteo?.batiment_materiaux_anciens) === 1 &&
|
|
52
|
+
[1, 2].includes(inertieId)
|
|
53
|
+
? 1
|
|
54
|
+
: 0
|
|
55
|
+
}
|
|
26
56
|
};
|
|
27
57
|
}
|
|
28
58
|
|
|
29
59
|
/**
|
|
30
60
|
* La zone climatique à partir du type de DPE
|
|
31
61
|
* @param dpe {Dpe}
|
|
32
|
-
* @return {{id:
|
|
62
|
+
* @return {{id: string, value: string}}
|
|
33
63
|
*/
|
|
34
64
|
#zoneClimatique(dpe) {
|
|
35
65
|
const zoneClimatiqueId = parseInt(dpe.logement.meteo?.enum_zone_climatique_id);
|
|
@@ -39,6 +69,19 @@ export class ContexteBuilder {
|
|
|
39
69
|
};
|
|
40
70
|
}
|
|
41
71
|
|
|
72
|
+
/**
|
|
73
|
+
* La classe d'altitude à partir du type de DPE
|
|
74
|
+
* @param dpe {Dpe}
|
|
75
|
+
* @return {{id: string, value: string}}
|
|
76
|
+
*/
|
|
77
|
+
#altitude(dpe) {
|
|
78
|
+
const altitudeId = parseInt(dpe.logement.meteo?.enum_classe_altitude_id);
|
|
79
|
+
return {
|
|
80
|
+
id: altitudeId.toString(),
|
|
81
|
+
value: enums.classe_altitude[altitudeId]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
42
85
|
/**
|
|
43
86
|
* Si un générateur de chauffage par résistance électrique existe, alors effet joule vaut vrai
|
|
44
87
|
* @param dpe {Dpe}
|
|
@@ -89,8 +132,12 @@ export class ContexteBuilder {
|
|
|
89
132
|
|
|
90
133
|
if ([1, 14, 18].includes(methodeApplication)) {
|
|
91
134
|
return TypeDpe.MAISON;
|
|
92
|
-
} else if (
|
|
135
|
+
} else if (
|
|
136
|
+
[2, 3, 4, 5, 15, 16, 19, 20, 22, 23, 24, 25, 31, 32, 35, 36, 37].includes(methodeApplication)
|
|
137
|
+
) {
|
|
93
138
|
return TypeDpe.APPARTEMENT;
|
|
139
|
+
} else if ([10, 11, 12, 13, 33, 34, 38, 39, 40].includes(methodeApplication)) {
|
|
140
|
+
return TypeDpe.APPARTEMENT_A_PARTIR_IMMEUBLE;
|
|
94
141
|
}
|
|
95
142
|
return TypeDpe.IMMEUBLE;
|
|
96
143
|
}
|