@open3cl/engine 1.8.49 → 1.8.51
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/13.2_generateur_combustion.js +99 -2
- package/13.2_generateur_combustion.spec.js +196 -1
- package/13.2_generateur_combustion_pdim.js +212 -0
- package/13.2_generateur_combustion_pdim.spec.js +259 -0
- package/14_generateur_ecs.js +4 -1
- package/README.md +14 -14
- package/conso.js +115 -37
- package/conso.spec.js +188 -10
- package/engine.js +13 -5
- package/engine.spec.js +18 -0
- package/features/engine/domain/ch/generateur-ch.service.js +61 -5
- package/features/engine/domain/ch/generateur-ch.service.spec.js +101 -0
- package/package.json +1 -1
|
@@ -9,6 +9,11 @@ import { updateGenerateurPacs } from './13.2_generateur_pac.js';
|
|
|
9
9
|
import getFicheTechnique from './ficheTechnique.js';
|
|
10
10
|
import { evaluateFormula as evaluateTvFormula } from './formula.js';
|
|
11
11
|
import { conventionPuissanceNominale } from './13.2_generateur_combustion_pn.js';
|
|
12
|
+
import {
|
|
13
|
+
anneeInstallationGenerateur,
|
|
14
|
+
pnEstimeeDimensionnement,
|
|
15
|
+
valeurChaudiereMurale
|
|
16
|
+
} from './13.2_generateur_combustion_pdim.js';
|
|
12
17
|
|
|
13
18
|
function criterePn(Pn, matcher) {
|
|
14
19
|
let critere_list = tvColumnLines('generateur_combustion', 'critere_pn', matcher);
|
|
@@ -144,6 +149,95 @@ export function pnEstimee(GV, tbase, ratioSurface = 1) {
|
|
|
144
149
|
return (prorata * 1.2 * GV * (19 - tbase)) / 0.95 ** 3;
|
|
145
150
|
}
|
|
146
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Pose murale d'une chaudière, lue dans la sous-fiche technique « Chaudière murale » (catégorie 7
|
|
154
|
+
* pour le chauffage, 8 pour l'ECS) du générateur.
|
|
155
|
+
*
|
|
156
|
+
* @param dpe {FullDpe}
|
|
157
|
+
* @param de {Donnee_entree}
|
|
158
|
+
* @param type {'ch' | 'ecs'}
|
|
159
|
+
* @returns {boolean|undefined} undefined si non renseigné
|
|
160
|
+
*/
|
|
161
|
+
export function chaudiereMurale(dpe, de, type) {
|
|
162
|
+
const fiche = getFicheTechnique(dpe, type === 'ch' ? '7' : '8', 'Chaudière murale', [
|
|
163
|
+
de.description
|
|
164
|
+
]);
|
|
165
|
+
return valeurChaudiereMurale(fiche?.valeur);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Volume de stockage (L) de la production d'ECS assurée par un générateur de chauffage mixte :
|
|
170
|
+
* générateur ECS mixte de même `reference_generateur_mixte`, sinon générateur ECS mixte unique.
|
|
171
|
+
*
|
|
172
|
+
* @param dpe {FullDpe}
|
|
173
|
+
* @param de {Donnee_entree} données du générateur de chauffage
|
|
174
|
+
* @returns {number|undefined}
|
|
175
|
+
*/
|
|
176
|
+
export function volumeStockageEcsMixte(dpe, de) {
|
|
177
|
+
const liste = (x) => (x === undefined || x === null ? [] : Array.isArray(x) ? x : [x]);
|
|
178
|
+
const generateursEcsMixtes = liste(dpe?.logement?.installation_ecs_collection?.installation_ecs)
|
|
179
|
+
.flatMap((installation) => liste(installation.generateur_ecs_collection?.generateur_ecs))
|
|
180
|
+
.filter((generateur) => String(generateur?.donnee_entree?.enum_usage_generateur_id) === '3');
|
|
181
|
+
|
|
182
|
+
const reference = de.reference_generateur_mixte;
|
|
183
|
+
const jumeau =
|
|
184
|
+
(reference !== undefined &&
|
|
185
|
+
reference !== null &&
|
|
186
|
+
generateursEcsMixtes.find(
|
|
187
|
+
(generateur) =>
|
|
188
|
+
String(generateur.donnee_entree.reference_generateur_mixte) === String(reference)
|
|
189
|
+
)) ||
|
|
190
|
+
(generateursEcsMixtes.length === 1 ? generateursEcsMixtes[0] : undefined);
|
|
191
|
+
|
|
192
|
+
return jumeau?.donnee_entree.volume_stockage;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Puissance nominale estimée (W) d'un générateur à combustion dont `pn` est absente.
|
|
197
|
+
*
|
|
198
|
+
* Méthode 3CL-DPE 2021 §13.2.2.4 : Pdim = max(Pch ; Pecs), puis table Pdim → Pn pour les chaudières
|
|
199
|
+
* (cf. 13.2_generateur_combustion_pdim.js). La méthode ne vise que les générateurs individuels :
|
|
200
|
+
* pour une installation collective, Pch est conservée (comportement historique).
|
|
201
|
+
*
|
|
202
|
+
* @param dpe {FullDpe}
|
|
203
|
+
* @param de {Donnee_entree} données du générateur
|
|
204
|
+
* @param type {'ch' | 'ecs'}
|
|
205
|
+
* @param pch {number} Pch (W) proratisée à la surface desservie
|
|
206
|
+
* @param optionsPn {{installationIndividuelle?: boolean, volumeStockage?: number}}
|
|
207
|
+
* @returns {number} Pn (W)
|
|
208
|
+
*/
|
|
209
|
+
export function pnEstimeeGenerateur(dpe, de, type, pch, optionsPn = {}) {
|
|
210
|
+
const installationIndividuelle =
|
|
211
|
+
optionsPn.installationIndividuelle ?? String(de.enum_type_installation_id) === '1';
|
|
212
|
+
if (!installationIndividuelle) {
|
|
213
|
+
return pch;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const usage = String(de.enum_usage_generateur_id);
|
|
217
|
+
const usageEcs = type === 'ecs' || usage === '3';
|
|
218
|
+
const usageChauffage = type === 'ch' || usage === '3';
|
|
219
|
+
const volumeStockage =
|
|
220
|
+
optionsPn.volumeStockage ??
|
|
221
|
+
(type === 'ecs' ? de.volume_stockage : usageEcs ? volumeStockageEcsMixte(dpe, de) : undefined);
|
|
222
|
+
|
|
223
|
+
const libelleTypeGenerateur =
|
|
224
|
+
enums[`type_generateur_${type}`]?.[de[`enum_type_generateur_${type}_id`]];
|
|
225
|
+
|
|
226
|
+
return pnEstimeeDimensionnement({
|
|
227
|
+
pch,
|
|
228
|
+
volumeStockage,
|
|
229
|
+
usageEcs,
|
|
230
|
+
usageChauffage,
|
|
231
|
+
libelleTypeGenerateur,
|
|
232
|
+
murale: chaudiereMurale(dpe, de, type),
|
|
233
|
+
anneeInstallation: anneeInstallationGenerateur(
|
|
234
|
+
de.annee_installation,
|
|
235
|
+
dpe?.logement?.caracteristique_generale?.annee_construction,
|
|
236
|
+
libelleTypeGenerateur
|
|
237
|
+
)
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
147
241
|
/**
|
|
148
242
|
* Si la méthode de saisie n'est pas "Valeur forfaitaire" mais "caractéristiques saisies"
|
|
149
243
|
* Documentation 3CL : "Pour les installations récentes ou recommandées, les caractéristiques réelles des chaudières présentées sur les bases
|
|
@@ -163,6 +257,8 @@ export function pnEstimee(GV, tbase, ratioSurface = 1) {
|
|
|
163
257
|
* @param methodeSaisie {number} méthode de saisie des caractéristiques du générateur
|
|
164
258
|
* @param ratioSurface {number} part de la surface du logement desservie par le générateur
|
|
165
259
|
* (Sh_installation / Sh), utilisée pour proratiser la puissance nominale estimée (§13.2.2.4)
|
|
260
|
+
* @param optionsPn {{installationIndividuelle?: boolean, volumeStockage?: number}} données de
|
|
261
|
+
* l'installation pour l'estimation de Pn par Pdim (§13.2.2.4, cf. pnEstimeeGenerateur)
|
|
166
262
|
*/
|
|
167
263
|
export function tv_generateur_combustion(
|
|
168
264
|
dpe,
|
|
@@ -172,7 +268,8 @@ export function tv_generateur_combustion(
|
|
|
172
268
|
GV,
|
|
173
269
|
tbase,
|
|
174
270
|
methodeSaisie,
|
|
175
|
-
ratioSurface = 1
|
|
271
|
+
ratioSurface = 1,
|
|
272
|
+
optionsPn = {}
|
|
176
273
|
) {
|
|
177
274
|
const typeGenerateurKey = `enum_type_generateur_${type}_id`;
|
|
178
275
|
let enumTypeGenerateurId = de[typeGenerateurKey];
|
|
@@ -240,7 +337,7 @@ export function tv_generateur_combustion(
|
|
|
240
337
|
} else {
|
|
241
338
|
// Calcul de la puissance nominale si non définie
|
|
242
339
|
if (!di.pn) {
|
|
243
|
-
di.pn = pnEstimee(GV, tbase, ratioSurface);
|
|
340
|
+
di.pn = pnEstimeeGenerateur(dpe, de, type, pnEstimee(GV, tbase, ratioSurface), optionsPn);
|
|
244
341
|
}
|
|
245
342
|
|
|
246
343
|
selectionLigne = (pn, ratio) => {
|
|
@@ -59,6 +59,14 @@ vi.mock('./ficheTechnique.js', () => ({
|
|
|
59
59
|
vi.mock('./13.2_generateur_combustion_pn.js', () => ({
|
|
60
60
|
conventionPuissanceNominale: vi.fn((pn, ratio) => ({ pn, ratio, convention: 'individualisee' }))
|
|
61
61
|
}));
|
|
62
|
+
/**
|
|
63
|
+
* Estimation Pdim → Pn (issue #271) : testée dans son propre spec. Par défaut, le double renvoie Pch.
|
|
64
|
+
*/
|
|
65
|
+
vi.mock('./13.2_generateur_combustion_pdim.js', () => ({
|
|
66
|
+
pnEstimeeDimensionnement: vi.fn(({ pch }) => pch),
|
|
67
|
+
anneeInstallationGenerateur: vi.fn(() => 2018),
|
|
68
|
+
valeurChaudiereMurale: vi.fn((v) => (v === 'oui' ? true : v === 'non' ? false : undefined))
|
|
69
|
+
}));
|
|
62
70
|
|
|
63
71
|
const {
|
|
64
72
|
tv_generateur_combustion,
|
|
@@ -69,8 +77,13 @@ const {
|
|
|
69
77
|
caracteristiquesGenerateurCombustion,
|
|
70
78
|
puissanceFormuleQp0,
|
|
71
79
|
PN_MAX_QP0_CHAUDIERE_GAZ,
|
|
72
|
-
pnEstimee
|
|
80
|
+
pnEstimee,
|
|
81
|
+
pnEstimeeGenerateur,
|
|
82
|
+
chaudiereMurale,
|
|
83
|
+
volumeStockageEcsMixte
|
|
73
84
|
} = await import('./13.2_generateur_combustion.js');
|
|
85
|
+
const { pnEstimeeDimensionnement, anneeInstallationGenerateur } =
|
|
86
|
+
await import('./13.2_generateur_combustion_pdim.js');
|
|
74
87
|
const { tv, tvColumnLines } = await import('./utils.js');
|
|
75
88
|
const { conventionPuissanceNominale } = await import('./13.2_generateur_combustion_pn.js');
|
|
76
89
|
const { updateGenerateurBouilleurs } = await import('./13.2_generateur_combustion_bouilleur.js');
|
|
@@ -1479,3 +1492,185 @@ describe('pnEstimee - puissance nominale estimée (issue #264)', () => {
|
|
|
1479
1492
|
expect(pnEstimee(200, -9, ratio)).toBeCloseTo(PCH_LOGEMENT, 9);
|
|
1480
1493
|
});
|
|
1481
1494
|
});
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Pn estimée par la puissance de dimensionnement (issue #271).
|
|
1498
|
+
* @see : Methode_de_calcul_3CL_DPE_2021-338.pdf - §13.2.2.4
|
|
1499
|
+
*/
|
|
1500
|
+
describe('pnEstimeeGenerateur - Pdim = max(Pch ; Pecs) et table Pdim → Pn (issue #271)', () => {
|
|
1501
|
+
const dpeAvecEcsMixte = (generateursEcs) => ({
|
|
1502
|
+
logement: {
|
|
1503
|
+
caracteristique_generale: { annee_construction: '1975' },
|
|
1504
|
+
installation_ecs_collection: {
|
|
1505
|
+
installation_ecs: [{ generateur_ecs_collection: { generateur_ecs: generateursEcs } }]
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
beforeEach(() => {
|
|
1511
|
+
vi.mocked(pnEstimeeDimensionnement).mockClear();
|
|
1512
|
+
vi.mocked(anneeInstallationGenerateur).mockClear();
|
|
1513
|
+
vi.mocked(getFicheTechnique).mockReset();
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
test('installation collective : Pch conservée, pas de table', () => {
|
|
1517
|
+
const de = { enum_type_installation_id: '2', enum_type_generateur_ch_id: '89' };
|
|
1518
|
+
expect(pnEstimeeGenerateur({}, de, 'ch', 7800)).toBe(7800);
|
|
1519
|
+
expect(pnEstimeeDimensionnement).not.toHaveBeenCalled();
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
test('option installationIndividuelle prioritaire sur la donnée du générateur', () => {
|
|
1523
|
+
const de = { enum_type_installation_id: '1', enum_type_generateur_ecs_id: 'A' };
|
|
1524
|
+
expect(pnEstimeeGenerateur({}, de, 'ecs', 7800, { installationIndividuelle: false })).toBe(
|
|
1525
|
+
7800
|
|
1526
|
+
);
|
|
1527
|
+
expect(pnEstimeeDimensionnement).not.toHaveBeenCalled();
|
|
1528
|
+
});
|
|
1529
|
+
|
|
1530
|
+
test('chaudière de chauffage seul : paramètres transmis (libellé, pose murale, année)', () => {
|
|
1531
|
+
vi.mocked(getFicheTechnique).mockReturnValue({ valeur: 'oui' });
|
|
1532
|
+
const dpe = { logement: { caracteristique_generale: { annee_construction: '1975' } } };
|
|
1533
|
+
const de = {
|
|
1534
|
+
description: 'Chaudière gaz',
|
|
1535
|
+
enum_type_installation_id: '1',
|
|
1536
|
+
enum_usage_generateur_id: '1',
|
|
1537
|
+
enum_type_generateur_ch_id: '89',
|
|
1538
|
+
annee_installation: '2010'
|
|
1539
|
+
};
|
|
1540
|
+
pnEstimeeGenerateur(dpe, de, 'ch', 7800);
|
|
1541
|
+
|
|
1542
|
+
expect(getFicheTechnique).toHaveBeenCalledWith(dpe, '7', 'Chaudière murale', ['Chaudière gaz']);
|
|
1543
|
+
expect(anneeInstallationGenerateur).toHaveBeenCalledWith(
|
|
1544
|
+
'2010',
|
|
1545
|
+
'1975',
|
|
1546
|
+
'chaudière gaz standard 2001-2015'
|
|
1547
|
+
);
|
|
1548
|
+
expect(pnEstimeeDimensionnement).toHaveBeenCalledWith({
|
|
1549
|
+
pch: 7800,
|
|
1550
|
+
volumeStockage: undefined,
|
|
1551
|
+
usageEcs: false,
|
|
1552
|
+
usageChauffage: true,
|
|
1553
|
+
libelleTypeGenerateur: 'chaudière gaz standard 2001-2015',
|
|
1554
|
+
murale: true,
|
|
1555
|
+
anneeInstallation: 2018
|
|
1556
|
+
});
|
|
1557
|
+
});
|
|
1558
|
+
|
|
1559
|
+
test('chaudière mixte : volume de stockage du générateur ECS jumeau (reference_generateur_mixte)', () => {
|
|
1560
|
+
const dpe = dpeAvecEcsMixte([
|
|
1561
|
+
{
|
|
1562
|
+
donnee_entree: {
|
|
1563
|
+
enum_usage_generateur_id: '3',
|
|
1564
|
+
reference_generateur_mixte: 'A',
|
|
1565
|
+
volume_stockage: 0
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
donnee_entree: {
|
|
1570
|
+
enum_usage_generateur_id: '3',
|
|
1571
|
+
reference_generateur_mixte: 'B',
|
|
1572
|
+
volume_stockage: 150
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
]);
|
|
1576
|
+
const de = {
|
|
1577
|
+
enum_type_installation_id: '1',
|
|
1578
|
+
enum_usage_generateur_id: '3',
|
|
1579
|
+
enum_type_generateur_ch_id: '89',
|
|
1580
|
+
reference_generateur_mixte: 'B'
|
|
1581
|
+
};
|
|
1582
|
+
pnEstimeeGenerateur(dpe, de, 'ch', 7800);
|
|
1583
|
+
expect(pnEstimeeDimensionnement).toHaveBeenCalledWith(
|
|
1584
|
+
expect.objectContaining({ volumeStockage: 150, usageEcs: true, usageChauffage: true })
|
|
1585
|
+
);
|
|
1586
|
+
});
|
|
1587
|
+
|
|
1588
|
+
test('générateur ECS : volume de stockage du générateur, usage ECS seul', () => {
|
|
1589
|
+
vi.mocked(getFicheTechnique).mockReturnValue({ valeur: 'non' });
|
|
1590
|
+
const de = {
|
|
1591
|
+
description: 'Chaudière gaz',
|
|
1592
|
+
enum_usage_generateur_id: '2',
|
|
1593
|
+
enum_type_generateur_ecs_id: 'A',
|
|
1594
|
+
volume_stockage: 10
|
|
1595
|
+
};
|
|
1596
|
+
pnEstimeeGenerateur({}, de, 'ecs', 7800, { installationIndividuelle: true });
|
|
1597
|
+
expect(getFicheTechnique).toHaveBeenCalledWith({}, '8', 'Chaudière murale', ['Chaudière gaz']);
|
|
1598
|
+
expect(pnEstimeeDimensionnement).toHaveBeenCalledWith(
|
|
1599
|
+
expect.objectContaining({
|
|
1600
|
+
volumeStockage: 10,
|
|
1601
|
+
usageEcs: true,
|
|
1602
|
+
usageChauffage: false,
|
|
1603
|
+
libelleTypeGenerateur: 'chaudière gaz',
|
|
1604
|
+
murale: false
|
|
1605
|
+
})
|
|
1606
|
+
);
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
test('volume de stockage transmis en option prioritaire', () => {
|
|
1610
|
+
const de = { enum_type_installation_id: '1', enum_usage_generateur_id: '2' };
|
|
1611
|
+
pnEstimeeGenerateur({}, de, 'ecs', 7800, { volumeStockage: 300 });
|
|
1612
|
+
expect(pnEstimeeDimensionnement).toHaveBeenCalledWith(
|
|
1613
|
+
expect.objectContaining({ volumeStockage: 300 })
|
|
1614
|
+
);
|
|
1615
|
+
});
|
|
1616
|
+
|
|
1617
|
+
test('tv_generateur_combustion : pn absente estimée via pnEstimeeGenerateur', () => {
|
|
1618
|
+
vi.mocked(pnEstimeeDimensionnement).mockReturnValueOnce(24000);
|
|
1619
|
+
vi.mocked(tv).mockReturnValue({ tv_generateur_combustion_id: '1', rpn: '90', rpint: '90' });
|
|
1620
|
+
const di = {};
|
|
1621
|
+
const de = {
|
|
1622
|
+
enum_type_generateur_ch_id: '89',
|
|
1623
|
+
enum_type_installation_id: '1',
|
|
1624
|
+
enum_usage_generateur_id: '1'
|
|
1625
|
+
};
|
|
1626
|
+
tv_generateur_combustion({}, di, de, 'ch', 200, -9, 1);
|
|
1627
|
+
expect(di.pn).toBe(24000);
|
|
1628
|
+
});
|
|
1629
|
+
});
|
|
1630
|
+
|
|
1631
|
+
describe('volumeStockageEcsMixte - volume de stockage de l’ECS d’un générateur mixte', () => {
|
|
1632
|
+
const ecs = (usage, reference, volume) => ({
|
|
1633
|
+
donnee_entree: {
|
|
1634
|
+
enum_usage_generateur_id: usage,
|
|
1635
|
+
reference_generateur_mixte: reference,
|
|
1636
|
+
volume_stockage: volume
|
|
1637
|
+
}
|
|
1638
|
+
});
|
|
1639
|
+
const dpe = (generateurs) => ({
|
|
1640
|
+
logement: {
|
|
1641
|
+
installation_ecs_collection: {
|
|
1642
|
+
installation_ecs: { generateur_ecs_collection: { generateur_ecs: generateurs } }
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
test('jumeau par reference_generateur_mixte', () => {
|
|
1648
|
+
const d = dpe([ecs('3', 'R1', 80), ecs('3', 'R2', 200)]);
|
|
1649
|
+
expect(volumeStockageEcsMixte(d, { reference_generateur_mixte: 'R2' })).toBe(200);
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
test('sans référence : générateur ECS mixte unique', () => {
|
|
1653
|
+
const d = dpe([ecs('2', undefined, 300), ecs('3', undefined, 0)]);
|
|
1654
|
+
expect(volumeStockageEcsMixte(d, {})).toBe(0);
|
|
1655
|
+
});
|
|
1656
|
+
|
|
1657
|
+
test('plusieurs générateurs mixtes sans référence commune : volume inconnu', () => {
|
|
1658
|
+
const d = dpe([ecs('3', 'R1', 80), ecs('3', 'R2', 200)]);
|
|
1659
|
+
expect(volumeStockageEcsMixte(d, { reference_generateur_mixte: 'R3' })).toBeUndefined();
|
|
1660
|
+
expect(volumeStockageEcsMixte(d, {})).toBeUndefined();
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
test('aucune installation ECS', () => {
|
|
1664
|
+
expect(volumeStockageEcsMixte({}, {})).toBeUndefined();
|
|
1665
|
+
expect(
|
|
1666
|
+
volumeStockageEcsMixte(dpe(ecs('3', 'R', 50)), { reference_generateur_mixte: 'R' })
|
|
1667
|
+
).toBe(50);
|
|
1668
|
+
});
|
|
1669
|
+
});
|
|
1670
|
+
|
|
1671
|
+
describe('chaudiereMurale - sous-fiche « Chaudière murale »', () => {
|
|
1672
|
+
test('fiche absente : pose inconnue', () => {
|
|
1673
|
+
vi.mocked(getFicheTechnique).mockReturnValue(null);
|
|
1674
|
+
expect(chaudiereMurale({}, { description: 'x' }, 'ch')).toBeUndefined();
|
|
1675
|
+
});
|
|
1676
|
+
});
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimation de la puissance nominale d'un générateur à combustion individuel lorsque `pn` n'est
|
|
3
|
+
* pas connue (repli du moteur quand `donnee_intermediaire.pn` est absente).
|
|
4
|
+
*
|
|
5
|
+
* Méthode 3CL-DPE 2021, §13.2.2.4 « Calcul des puissances nominales » (p.90-91) :
|
|
6
|
+
* 1. Pch = Sh1/Shtot × 1,2 × GV × (19 − Tbase) / (1000 × 0,95³) (cf. `pnEstimee`)
|
|
7
|
+
* 2. Pecs selon le type de production d'ECS (volume de stockage Vs) ;
|
|
8
|
+
* 3. Pdim = max(Pch ; Pecs) ;
|
|
9
|
+
* 4. Pn des chaudières lue dans la table Pdim → Pn (chaudières murales installées avant 2006 ou
|
|
10
|
+
* chaudières au sol / chaudières murales installées à partir de 2006).
|
|
11
|
+
*
|
|
12
|
+
* Les autres générateurs à combustion (radiateurs gaz, générateurs d'air chaud, poêles,
|
|
13
|
+
* accumulateurs, chauffe-eau…) conservent Pn = Pdim.
|
|
14
|
+
*
|
|
15
|
+
* Le moteur de référence (Tribu) ne fait pas cette estimation (Pn est une donnée d'entrée
|
|
16
|
+
* obligatoire) : elle relève du logiciel de saisie et sert surtout aux saisies incomplètes et aux
|
|
17
|
+
* recommandations.
|
|
18
|
+
*
|
|
19
|
+
* @see Methode_de_calcul_3CL_DPE_2021-338.pdf - §13.2.2.4 Calcul des puissances nominales (p.90-91)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Année à partir de laquelle les chaudières murales relèvent de la seconde colonne de la table
|
|
24
|
+
* Pdim → Pn.
|
|
25
|
+
*/
|
|
26
|
+
export const ANNEE_CHAUDIERE_MURALE_RECENTE = 2006;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Table Pdim → Pn (kW) des chaudières : [Pdim max (kW), Pn murale < 2006 ou sol, Pn murale ≥ 2006].
|
|
30
|
+
* Au-delà de 40 kW : Pn = (Partie entière(Pdim / 5) + 1) × 5 pour les deux colonnes.
|
|
31
|
+
*/
|
|
32
|
+
const TABLE_PDIM_PN = [
|
|
33
|
+
[5, 18, 5],
|
|
34
|
+
[10, 18, 10],
|
|
35
|
+
[13, 18, 13],
|
|
36
|
+
[18, 18, 18],
|
|
37
|
+
[24, 24, 24],
|
|
38
|
+
[28, 28, 28],
|
|
39
|
+
[32, 32, 32],
|
|
40
|
+
[40, 40, 40]
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Puissance de dimensionnement nécessaire pour l'ECS (kW) selon le volume de stockage (L).
|
|
45
|
+
*
|
|
46
|
+
* | Type de production | Volume de stockage | Pecs (kW) |
|
|
47
|
+
* |--------------------|--------------------|----------------------------|
|
|
48
|
+
* | Instantanée | Vs = 0 | 21 |
|
|
49
|
+
* | Semi-instantanée | 0 < Vs ≤ 20 | 21 − 0,8 × Vs |
|
|
50
|
+
* | Semi-accumulation | 20 < Vs ≤ 150 | 5 − 1,751 × (Vs − 20) / 65 |
|
|
51
|
+
* | Accumulation | 150 < Vs | (7,14 × Vs + 428) / 1000 |
|
|
52
|
+
*
|
|
53
|
+
* Formules reprises telles que publiées (p.91).
|
|
54
|
+
*
|
|
55
|
+
* @param volumeStockage {number|string|undefined} Vs (L)
|
|
56
|
+
* @returns {number|undefined} Pecs (kW), undefined si le volume n'est pas renseigné
|
|
57
|
+
*/
|
|
58
|
+
export function puissanceEcs(volumeStockage) {
|
|
59
|
+
if (volumeStockage === undefined || volumeStockage === null || volumeStockage === '') {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const vs = Number(volumeStockage);
|
|
63
|
+
if (!Number.isFinite(vs) || vs < 0) return undefined;
|
|
64
|
+
|
|
65
|
+
if (vs === 0) return 21;
|
|
66
|
+
if (vs <= 20) return 21 - 0.8 * vs;
|
|
67
|
+
if (vs <= 150) return 5 - (1.751 * (vs - 20)) / 65;
|
|
68
|
+
return (7.14 * vs + 428) / 1000;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Pn (kW) d'une chaudière à partir de sa puissance de dimensionnement (table §13.2.2.4).
|
|
73
|
+
*
|
|
74
|
+
* @param pdim {number} Pdim (kW)
|
|
75
|
+
* @param muraleRecente {boolean} true pour une chaudière murale installée à partir de 2006,
|
|
76
|
+
* false pour une chaudière murale installée avant 2006 ou une chaudière au sol
|
|
77
|
+
* @returns {number} Pn (kW)
|
|
78
|
+
*/
|
|
79
|
+
export function pnChaudiere(pdim, muraleRecente) {
|
|
80
|
+
for (const [pdimMax, pnAncienneOuSol, pnMuraleRecente] of TABLE_PDIM_PN) {
|
|
81
|
+
if (pdim <= pdimMax) {
|
|
82
|
+
return muraleRecente ? pnMuraleRecente : pnAncienneOuSol;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return (Math.floor(pdim / 5) + 1) * 5;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Le générateur est-il une chaudière (table Pdim → Pn) ?
|
|
90
|
+
* Les « chaudière(s) … multi bâtiment modélisée comme un réseau de chaleur » ne sont pas
|
|
91
|
+
* concernées (générateurs collectifs).
|
|
92
|
+
*
|
|
93
|
+
* @param libelleTypeGenerateur {string|undefined} libellé enum_type_generateur_ch / _ecs
|
|
94
|
+
* @returns {boolean}
|
|
95
|
+
*/
|
|
96
|
+
export function isChaudiere(libelleTypeGenerateur) {
|
|
97
|
+
const libelle = (libelleTypeGenerateur ?? '').toString().toLowerCase();
|
|
98
|
+
return libelle.includes('chaudière') && !libelle.includes('réseau de chaleur');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Intervalle [min ; max] des années d'installation possibles d'après le libellé du type de
|
|
103
|
+
* générateur (« avant 1981 », « 2001-2015 », « après 2015 », « à partir de 2012 »…).
|
|
104
|
+
*
|
|
105
|
+
* @param libelleTypeGenerateur {string|undefined}
|
|
106
|
+
* @returns {{min: number, max: number}}
|
|
107
|
+
*/
|
|
108
|
+
export function periodeInstallationLibelle(libelleTypeGenerateur) {
|
|
109
|
+
const libelle = (libelleTypeGenerateur ?? '').toString().toLowerCase();
|
|
110
|
+
let match = libelle.match(/(\d{4})\s*-\s*(\d{4})/);
|
|
111
|
+
if (match) return { min: Number(match[1]), max: Number(match[2]) };
|
|
112
|
+
|
|
113
|
+
match = libelle.match(/avant (\d{4})/);
|
|
114
|
+
if (match) return { min: -Infinity, max: Number(match[1]) - 1 };
|
|
115
|
+
|
|
116
|
+
match = libelle.match(/(?:après|à partir de) (\d{4})/);
|
|
117
|
+
if (match) {
|
|
118
|
+
// « après 2015 » succède à « 2001-2015 » : 2015 appartient déjà à la période précédente
|
|
119
|
+
return { min: Number(match[1]) + (libelle.includes('après') ? 1 : 0), max: Infinity };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return { min: -Infinity, max: Infinity };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Année d'installation du générateur : année saisie, sinon année de construction ramenée dans la
|
|
127
|
+
* période indiquée par le type de générateur (une « chaudière gaz à condensation après 2015 » d'un
|
|
128
|
+
* bâtiment de 1970 a été installée après 2015).
|
|
129
|
+
*
|
|
130
|
+
* @param anneeInstallation {number|string|undefined} année d'installation saisie
|
|
131
|
+
* @param anneeConstruction {number|string|undefined} année de construction du bâtiment
|
|
132
|
+
* @param libelleTypeGenerateur {string|undefined}
|
|
133
|
+
* @returns {number|undefined}
|
|
134
|
+
*/
|
|
135
|
+
export function anneeInstallationGenerateur(
|
|
136
|
+
anneeInstallation,
|
|
137
|
+
anneeConstruction,
|
|
138
|
+
libelleTypeGenerateur
|
|
139
|
+
) {
|
|
140
|
+
const saisie = parseInt(anneeInstallation, 10);
|
|
141
|
+
if (Number.isFinite(saisie)) return saisie;
|
|
142
|
+
|
|
143
|
+
const { min, max } = periodeInstallationLibelle(libelleTypeGenerateur);
|
|
144
|
+
const construction = parseInt(anneeConstruction, 10);
|
|
145
|
+
if (Number.isFinite(construction)) return Math.min(Math.max(construction, min), max);
|
|
146
|
+
|
|
147
|
+
// Période entièrement connue d'un seul côté de 2006 : la borne suffit
|
|
148
|
+
if (Number.isFinite(min) && min >= ANNEE_CHAUDIERE_MURALE_RECENTE) return min;
|
|
149
|
+
if (Number.isFinite(max) && max < ANNEE_CHAUDIERE_MURALE_RECENTE) return max;
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Valeur de la sous-fiche technique « Chaudière murale » → true (oui), false (non), undefined.
|
|
155
|
+
* @param valeur {string|undefined}
|
|
156
|
+
* @returns {boolean|undefined}
|
|
157
|
+
*/
|
|
158
|
+
export function valeurChaudiereMurale(valeur) {
|
|
159
|
+
const v = (valeur ?? '').toString().trim().toLowerCase();
|
|
160
|
+
if (v.startsWith('oui')) return true;
|
|
161
|
+
if (v.startsWith('non')) return false;
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Puissance nominale estimée (W) d'un générateur à combustion sans `pn` (§13.2.2.4).
|
|
167
|
+
*
|
|
168
|
+
* Choix de colonne de la table Pdim → Pn :
|
|
169
|
+
* - chaudière murale (fiche technique « Chaudière murale : oui ») installée à partir de 2006 →
|
|
170
|
+
* seconde colonne ;
|
|
171
|
+
* - chaudière au sol (« Chaudière murale : non ») ou installée avant 2006 → première colonne ;
|
|
172
|
+
* - type de pose inconnu → seconde colonne si installée à partir de 2006 (chaudières récentes
|
|
173
|
+
* majoritairement murales), première sinon.
|
|
174
|
+
*
|
|
175
|
+
* @param params {{
|
|
176
|
+
* pch: number, Pch (W), déjà proratisée à la surface desservie
|
|
177
|
+
* volumeStockage?: number|string, Vs (L) de la production d'ECS assurée par le générateur
|
|
178
|
+
* usageEcs?: boolean, le générateur produit de l'ECS (usage ECS ou mixte)
|
|
179
|
+
* usageChauffage?: boolean, le générateur assure le chauffage (défaut true)
|
|
180
|
+
* libelleTypeGenerateur?: string,
|
|
181
|
+
* murale?: boolean, pose murale (undefined si inconnue)
|
|
182
|
+
* anneeInstallation?: number année d'installation (undefined si inconnue)
|
|
183
|
+
* }}
|
|
184
|
+
* @returns {number} Pn (W)
|
|
185
|
+
*/
|
|
186
|
+
export function pnEstimeeDimensionnement({
|
|
187
|
+
pch,
|
|
188
|
+
volumeStockage,
|
|
189
|
+
usageEcs = false,
|
|
190
|
+
usageChauffage = true,
|
|
191
|
+
libelleTypeGenerateur,
|
|
192
|
+
murale,
|
|
193
|
+
anneeInstallation
|
|
194
|
+
}) {
|
|
195
|
+
const pchKw = usageChauffage ? pch / 1000 : 0;
|
|
196
|
+
const pecsKw = usageEcs ? puissanceEcs(volumeStockage) : undefined;
|
|
197
|
+
const pdim = Math.max(pchKw, pecsKw ?? 0);
|
|
198
|
+
|
|
199
|
+
// Aucune donnée exploitable pour l'ECS d'un générateur ECS seul : comportement historique (Pch)
|
|
200
|
+
if (!usageChauffage && pecsKw === undefined) {
|
|
201
|
+
return pch;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!isChaudiere(libelleTypeGenerateur)) {
|
|
205
|
+
return pdim * 1000;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const recente =
|
|
209
|
+
anneeInstallation !== undefined && anneeInstallation >= ANNEE_CHAUDIERE_MURALE_RECENTE;
|
|
210
|
+
const muraleRecente = recente && murale !== false;
|
|
211
|
+
return pnChaudiere(pdim, muraleRecente) * 1000;
|
|
212
|
+
}
|