Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/10_clim.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,22 @@ function tv_seer(di, de, du, zc_id) {
}
}

export default function calc_clim(clim, bfr, bfr_dep, zc_id, Sh) {
/**
* @param clim {object} climatisation
* @param bfr {number} besoin de froid du bâtiment
* @param bfr_dep {number} besoin de froid dépensier du bâtiment
* @param zc_id {string} zone climatique
* @param Sh {number} surface de référence du calcul (SH immeuble pour un DPE généré depuis l'immeuble)
* @param prorataLogement {number} part du logement dans la consommation de froid de l'installation
* (Sh_logement / SH_immeuble pour un DPE appartement généré à partir de l'immeuble, 1 sinon). Les
* données intermédiaires restent à l'échelle de l'installation, comme dans le DPE de référence ;
* le prorata n'est appliqué qu'à l'agrégation des consommations du logement (conso.js).
* @see https://github.com/Open3CL/engine/issues/303
*/
export default function calc_clim(clim, bfr, bfr_dep, zc_id, Sh, prorataLogement = 1) {
const de = clim.donnee_entree;
const di = clim.donnee_intermediaire || {};
const du = {};
const du = { prorata_logement: prorataLogement };

const rs = de.surface_clim / Sh;
di.besoin_fr = bfr * rs;
Expand Down
26 changes: 26 additions & 0 deletions src/10_clim.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,32 @@ describe('calc_clim - consommation de climatisation', () => {
expect(c.donnee_intermediaire.eer).toBe(3);
});

/**
* DPE appartement généré à partir de l'immeuble : la part du logement est transmise via
* donnee_utilisateur, les données intermédiaires restant à l'échelle de l'installation.
* @see https://github.com/Open3CL/engine/issues/303
*/
test('prorata logement : mémorisé, données intermédiaires à l’échelle de l’installation', () => {
tv.mockReturnValue({ tv_seer_id: '5', eer: 3 });
const c = clim({ surface_clim: 100, enum_methode_saisie_carac_sys_id: '1' });

calc_clim(c, 1000, 1500, '1', 100, 0.25);

expect(c.donnee_utilisateur.prorata_logement).toBe(0.25);
// inchangé par le prorata : 0.9 * 1000 / 3
expect(c.donnee_intermediaire.besoin_fr).toBeCloseTo(1000, 9);
expect(c.donnee_intermediaire.conso_fr).toBeCloseTo(300, 9);
});

test('prorata logement absent : 1 par défaut', () => {
tv.mockReturnValue({ tv_seer_id: '5', eer: 3 });
const c = clim({ surface_clim: 100, enum_methode_saisie_carac_sys_id: '1' });

calc_clim(c, 1000, 1500, '1', 100);

expect(c.donnee_utilisateur.prorata_logement).toBe(1);
});

test('aucune ligne forfaitaire trouvée : EER indéfini, conso non finie', () => {
tv.mockReturnValue(null);
const c = clim({ surface_clim: 50, enum_methode_saisie_carac_sys_id: '1' });
Expand Down
16 changes: 14 additions & 2 deletions src/conso.js
Original file line number Diff line number Diff line change
Expand Up @@ -983,6 +983,16 @@ function getChauffageConso(gen_ch, field, coef, prorataChauffage, prefix, facteu
}, 0);
}

/**
* Part du logement dans la consommation de froid d'une installation (1 par défaut), positionnée par
* calc_clim pour les DPE appartement générés à partir de l'immeuble (issue #303).
* @param fr {object} climatisation
* @return {number}
*/
export function prorataFroidLogement(fr) {
return fr.donnee_utilisateur?.prorata_logement ?? 1;
}

function calc_conso_pond(
Sh,
zc_id,
Expand Down Expand Up @@ -1086,13 +1096,15 @@ function calc_conso_pond(
ret.fr = fr_list.reduce((acc, fr) => {
const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');
const conso =
fr.donnee_intermediaire.conso_fr * (typeEnergie === 'électricité fr' ? fAc('fr') : 1);
fr.donnee_intermediaire.conso_fr *
prorataFroidLogement(fr) *
(typeEnergie === 'électricité fr' ? fAc('fr') : 1);

return acc + getConso(coef, typeEnergie, conso);
}, 0);

ret.fr_depensier = fr_list.reduce((acc, fr) => {
const conso = fr.donnee_intermediaire.conso_fr_depensier;
const conso = fr.donnee_intermediaire.conso_fr_depensier * prorataFroidLogement(fr);
const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');

return acc + getConso(coef, typeEnergie, conso);
Expand Down
46 changes: 45 additions & 1 deletion src/conso.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ const {
ARRETES_RESEAU_CHALEUR,
COEF_GES_AUTRES_RESEAUX_CHALEUR,
indexArreteReseauChaleur,
getContenuCo2ReseauChaleur
getContenuCo2ReseauChaleur,
prorataFroidLogement
} = await import('./conso.js');
const { tv } = await import('./utils.js');

Expand Down Expand Up @@ -298,6 +299,49 @@ describe('calc_conso - agrégation des consommations', () => {
expect(net.cout.cout_eclairage).toBeCloseTo(brut.cout.cout_eclairage, 9);
});

/**
* DPE appartement généré à partir de l'immeuble : conso de froid ramenée au logement par le
* prorata mémorisé dans donnee_utilisateur.prorata_logement.
* @see https://github.com/Open3CL/engine/issues/303
*/
test('froid : conso et conso dépensière proratisées au logement', () => {
const fr = (du) => [
{
donnee_entree: { enum_type_energie_id: '1' },
donnee_intermediaire: { conso_fr: 400, conso_fr_depensier: 1000 },
donnee_utilisateur: du
}
];
const plein = calc_conso(100, 1, 1, [], [], [], fr(undefined), 1, 1, DATE_DPE, coef_ep);
const lot = calc_conso(
100,
1,
1,
[],
[],
[],
fr({ prorata_logement: 0.25 }),
1,
1,
DATE_DPE,
coef_ep
);

expect(plein.ef_conso.conso_fr).toBeCloseTo(400, 9);
expect(lot.ef_conso.conso_fr).toBeCloseTo(100, 9);
expect(lot.ef_conso.conso_fr_depensier).toBeCloseTo(250, 9);
expect(lot.emission_ges.emission_ges_fr).toBeCloseTo(
plein.emission_ges.emission_ges_fr * 0.25,
9
);
});

test('prorataFroidLogement : valeur mémorisée, 1 par défaut', () => {
expect(prorataFroidLogement({ donnee_utilisateur: { prorata_logement: 0.3 } })).toBe(0.3);
expect(prorataFroidLogement({ donnee_utilisateur: {} })).toBe(1);
expect(prorataFroidLogement({})).toBe(1);
});

test('autoconsommation PV : froid électrique minoré, froid non électrique non minoré', () => {
const frElec = [
{
Expand Down
13 changes: 12 additions & 1 deletion src/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,18 @@ export function calcul_3cl(inputDpe, options) {

const bfr = apport_et_besoin.besoin_fr;
const bfr_dep = apport_et_besoin.besoin_fr_depensier;
clim.forEach((clim) => calc_clim(clim, bfr, bfr_dep, zc_id, ShChauffageAndEcs));
/**
* DPE appartement généré à partir de l'immeuble : besoin et conso de froid calculés à l'échelle de
* l'installation (immeuble), puis ramenés au logement au prorata Sh_logement / SH_immeuble, comme le
* chauffage et l'ECS (Tribu `Calcul_installation_froid.cs` l.62-64, `Calcul_batiment.cs`
* l.1114-1138).
* @see https://github.com/Open3CL/engine/issues/303
*/
const prorataFroid =
dpeGenereImmeuble && Number(ShChauffageAndEcs) > Number(Sh) && Number(Sh) > 0
? Number(Sh) / Number(ShChauffageAndEcs)
: 1;
clim.forEach((clim) => calc_clim(clim, bfr, bfr_dep, zc_id, ShChauffageAndEcs, prorataFroid));

/**
* La consommation ECS est obtenu pour certains types de DPE par virtualisation des générateurs collectifs en générateurs individuels virtuels
Expand Down
32 changes: 32 additions & 0 deletions src/engine.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,38 @@ describe('calcul_3cl - surfaces immeuble / appartement et prorata', () => {
// Auxiliaires ECS : Sh = surface logement, ramenée à l'immeuble dans le calcul.
expect(conso_aux_distribution_ecs.mock.calls[0][3]).toBe(80);
expect(conso_aux_distribution_ecs.mock.calls[0][4]).toBe(200);
// Froid : pas un DPE généré depuis l'immeuble, conso de froid non proratisée (#303).
expect(calc_clim.mock.calls[0][4]).toBe(200);
expect(calc_clim.mock.calls[0][5]).toBe(1);
});

/**
* @see https://github.com/Open3CL/engine/issues/303
*/
test.each(['10', '11', '12', '13', '33', '34', '38', '39', '40'])(
"DPE appartement généré à partir de l'immeuble (map %s) : conso de froid proratisée Sh / SH",
(mapId) => {
enums.methode_application_dpe_log = { [mapId]: 'dpe appartement généré immeuble' };
const dpe = makeDpe();
dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = mapId;

calcul_3cl(dpe, { sanitize: false });

// Besoin calculé sur SH immeuble (200), part du logement = 80 / 200.
expect(calc_clim.mock.calls[0][4]).toBe(200);
expect(calc_clim.mock.calls[0][5]).toBeCloseTo(0.4, 9);
}
);

test("DPE généré depuis l'immeuble avec SH immeuble ≤ Sh logement : prorata de froid neutre", () => {
enums.methode_application_dpe_log = { 10: 'dpe appartement généré immeuble' };
const dpe = makeDpe();
dpe.logement.caracteristique_generale.enum_methode_application_dpe_log_id = '10';
dpe.logement.caracteristique_generale.surface_habitable_immeuble = 80;

calcul_3cl(dpe, { sanitize: false });

expect(calc_clim.mock.calls[0][5]).toBe(1);
});

test('appartement : rapport SH immeuble / SH logement transmis au calcul du coût', () => {
Expand Down
2 changes: 0 additions & 2 deletions test/corpus/files/corpus_dpe.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2343,7 +2343,6 @@ N°DPE
2462E2975513I
2478E2292798R
2478E2345309I
2313E4450644F
2395E1959846L
2262E0408340V
2313E4060537C
Expand Down Expand Up @@ -7276,7 +7275,6 @@ N°DPE
2378E0897934A
2478E0437257S
2395E3575457I
2377E0818271A
2313E0617495K
2313E3972378J
2363E1036397Y
Expand Down