@open3cl/engine
Version:
Open Source 3CL-DPE engine
530 lines (469 loc) • 16.7 kB
JavaScript
import enums from './enums.js';
import calc_conso_eclairage from './16_conso_eclairage.js';
import tvs from './tv.js';
import { tv } from './utils.js';
const coef_ep = {
'électricité ch': 2.3,
'électricité ecs': 2.3,
'électricité fr': 2.3,
'électricité éclairage': 2.3,
'électricité auxiliaire': 2.3
};
// 31 mars 2021
// https://www.legifrance.gouv.fr/download/pdf?id=doxMrRr0wbfJVvtWjfDP4gHzzERt1iX0PtobthCE6A0=
const coef_ges = {
'bois – bûches': 0.03,
'bois – granulés (pellets) ou briquettes': 0.03,
'bois – plaquettes forestières': 0.024,
'bois – plaquettes d’industrie': 0.024,
'gaz naturel': 0.227,
'fioul domestique': 0.324,
charbon: 0.385,
propane: 0.272,
butane: 0.272,
gpl: 0.272,
"électricité d'origine renouvelable utilisée dans le bâtiment": 0,
'électricité ch': 0.079,
'électricité ecs': 0.065,
'électricité fr': 0.064,
'électricité éclairage': 0.069,
'électricité auxiliaire': 0.064
};
// annexe 7
// https://www.legifrance.gouv.fr/download/file/doxMrRr0wbfJVvtWjfDP4qE7zNsiFZL-4wqNyqoY-CA=/JOE_TEXTE
const coef_cout = {
'fioul domestique': 0.09142,
'réseau de chauffage urbain': 0.0787,
propane: 0.14305,
butane: 0.20027,
charbon: 0.02372,
'bois – granulés (pellets) ou briquettes': 0.05991,
'bois – bûches': 0.03201,
'bois – plaquettes forestières': 0.03201,
'bois – plaquettes d’industrie': 0.03201,
// https://www.legifrance.gouv.fr/download/pdf?id=7hpbVyq228foxHzNM7WleDImAyXlPNb9zULelSY01V8=
'gaz naturel': cout_gaz_naturel,
"électricité d'origine renouvelable utilisée dans le bâtiment": cout_electricite,
'électricité ch': cout_electricite,
'électricité ecs': cout_electricite,
'électricité fr': cout_electricite,
'électricité éclairage': cout_electricite,
'électricité auxiliaire': cout_electricite
};
/**
* Fonction utilitaire pour générer la clef à utiliser pour la table `coef_ges`.
* Le type_energie 'électricté' nécessite un suffixe : en fonction la destination d'usage,
* le coefficient est différent.
*
* @param type_energie {string} label de l'enum type_energie
* @param destination {'ch' | 'ecs' | 'éclairage'}
* @return {string} la clef à utiliser pour récupérer le coefficient depuis la table `coef_ges`
*/
function getCoefKey(type_energie, destination) {
if (type_energie === 'électricité') {
if (!['ch', 'ecs', 'éclairage'].includes(destination)) {
console.error(`Type d'électricité inconnu: ${destination}`);
}
return `électricité ${destination}`;
}
return type_energie;
}
function cout_gaz_naturel(cef) {
if (cef < 5009) return 0.11121 * cef;
else if (cef < 50055) return 230 + 0.06533 * cef;
else return 415 + 0.06164 * cef;
}
function cout_electricite(cef) {
if (cef < 1000) return 0.29007 * cef;
else if (cef < 2500) return 149 + 0.14066 * cef;
else if (cef < 5000) return 122 + 0.15176 * cef;
else if (cef < 15000) return 94 + 0.15735 * cef;
else return 56 + 0.15989 * cef;
}
function getConso(coef, type_energie, conso) {
// is coef is a function, execute it
if (!coef) return conso;
const coef_val = coef[type_energie];
if (typeof coef_val === 'function') {
const val = coef_val(conso);
return val;
}
if (coef_val) return coef_val * conso;
return conso;
}
/**
* Récupération du coefficient d'émission GES pour le générateur
* @param gen_ch {GenerateurChauffageItem||GenerateurEcsItem}
* @param suffix {'ch'|'ecs'}
* @returns {number}
*/
function getGesCoeffForGenerateur(gen_ch, suffix) {
const typeEnergie = getTypeEnergie(gen_ch.donnee_entree, suffix);
/**
* Cas spécifique des réseaux de chaleur urbain qui ont des coefficients différents en fonction de réseau de distribution
*/
if (typeEnergie === 'réseau de chauffage urbain') {
const identifiant_reseau = gen_ch.donnee_entree.identifiant_reseau_chaleur;
if (identifiant_reseau) {
const row = tv('reseau_chaleur_2022', { identifiant_reseau });
if (row) {
return row.contenu_co2_acv;
} else {
console.error(`
Aucun coefficient GES trouvé pour le réseau de chaleur ${identifiant_reseau}
`);
}
} else {
// Prendre la valeur pour "AUTRES RESEAUX DE CHALEUR"
return 0.385;
}
}
return coef_ges[typeEnergie] ?? 1;
}
export default function calc_conso(
Sh,
zc_id,
ca_id,
vt,
ch,
ecs,
fr,
prorataECS,
prorataChauffage
) {
const gen_ch = ch.reduce((acc, ch) => {
const generateur_chauffage = ch.generateur_chauffage_collection.generateur_chauffage;
generateur_chauffage.forEach((value) => {
// S'il existe une clé de repartition de chauffage, utilisation de celle-ci pour répartir la conso chauffage collectif à l'appartement
if (ch.donnee_entree.cle_repartition_ch === 1) {
value.donnee_entree.cle_repartition_ch = prorataChauffage;
} else {
value.donnee_entree.cle_repartition_ch =
ch.donnee_entree.cle_repartition_ch || prorataChauffage;
}
value.donnee_entree.enum_methode_calcul_conso_id =
ch.donnee_entree.enum_methode_calcul_conso_id;
value.donnee_entree.enum_type_installation_id = ch.donnee_entree.enum_type_installation_id;
(value.donnee_utilisateur = value.donnee_utilisateur || {}).coeffEmissionGes =
getGesCoeffForGenerateur(value, 'ch');
});
return acc.concat(generateur_chauffage);
}, []);
const gen_ecs = ecs.reduce((acc, ecs) => {
const generateur_ecs = ecs.generateur_ecs_collection.generateur_ecs;
if (prorataECS === 1) {
// S'il existe une clé de repartition ECS, utilisation de celle-ci pour répartir la conso ECS collective à l'appartement
generateur_ecs.forEach((value) => {
value.donnee_entree.cle_repartition_ecs =
(ecs.donnee_entree.cle_repartition_ecs || 1) * (ecs.donnee_entree.rdim || 1);
(value.donnee_utilisateur = value.donnee_utilisateur || {}).coeffEmissionGes =
getGesCoeffForGenerateur(value, 'ecs');
});
}
return acc.concat(generateur_ecs);
}, []);
const ret = {
ef_conso: calc_conso_pond(
Sh,
zc_id,
vt,
gen_ch,
gen_ecs,
fr,
'conso',
null,
prorataECS,
prorataChauffage
),
ep_conso: calc_conso_pond(
Sh,
zc_id,
vt,
gen_ch,
gen_ecs,
fr,
'ep_conso',
coef_ep,
prorataECS,
prorataChauffage
),
emission_ges: calc_conso_pond(
Sh,
zc_id,
vt,
gen_ch,
gen_ecs,
fr,
'emission_ges',
coef_ges,
prorataECS,
prorataChauffage
),
cout: calc_conso_pond(
Sh,
zc_id,
vt,
gen_ch,
gen_ecs,
fr,
'cout',
coef_cout,
prorataECS,
prorataChauffage
)
};
ret.ep_conso.classe_bilan_dpe = classe_bilan_dpe(
ret.ep_conso.ep_conso_5_usages_m2,
zc_id,
ca_id,
Sh
);
ret.emission_ges.classe_emission_ges = classe_emission_ges(
ret.emission_ges.emission_ges_5_usages_m2,
zc_id,
ca_id,
Sh
);
const energie_ids = [];
// find all type_energies in gen_ch and gen_ecs
gen_ch.forEach((gen_ch) => {
const id = gen_ch.donnee_entree.enum_type_energie_id;
if (!energie_ids.includes(id)) energie_ids.push(id);
});
gen_ecs.forEach((gen_ecs) => {
const id = gen_ecs.donnee_entree.enum_type_energie_id;
if (!energie_ids.includes(id)) energie_ids.push(id);
});
if (!energie_ids.includes('1')) energie_ids.push('1');
// calculate calc_conso_pond for each energy type
ret.sortie_par_energie_collection = {};
ret.sortie_par_energie_collection.sortie_par_energie = energie_ids.reduce((acc, energie_id) => {
const type_energie = enums.type_energie[energie_id];
let vt_en, fr_en;
if (type_energie === 'électricité') {
vt_en = vt;
fr_en = fr;
} else {
vt_en = [];
fr_en = [];
}
const gen_ch_en = gen_ch.filter(
(gen_ch) => gen_ch.donnee_entree.enum_type_energie_id === energie_id
);
const gen_ecs_en = gen_ecs.filter(
(gen_ecs) => gen_ecs.donnee_entree.enum_type_energie_id === energie_id
);
let conso_en = calc_conso_pond(
Sh,
zc_id,
vt_en,
gen_ch_en,
gen_ecs_en,
fr_en,
'',
null,
prorataECS,
prorataChauffage
);
conso_en = {
conso_ch: conso_en._ch,
conso_ecs: conso_en._ecs,
conso_5_usages: conso_en._5_usages,
emission_ges_ch: conso_en._ch * coef_ges[getCoefKey(type_energie, 'ch')],
emission_ges_ecs: conso_en._ecs * coef_ges[getCoefKey(type_energie, 'ecs')],
emission_ges_5_usages: conso_en._5_usages * coef_ges[type_energie] // TODO elec
};
conso_en.enum_type_energie_id = energie_id;
return acc.concat(conso_en);
}, []);
return ret;
}
export function classe_bilan_dpe(ep_conso_5_usages_m2, zc_id, ca_id, Sh) {
const ca = enums.classe_altitude[ca_id];
const cut = tvs.dpe_class_limit[ca][Math.round(Sh)] ?? [];
if (ep_conso_5_usages_m2 == null) return null;
if (ep_conso_5_usages_m2 < (cut['A'] ?? 70)) return 'A';
if (ep_conso_5_usages_m2 < (cut['B'] ?? 110)) return 'B';
if (ep_conso_5_usages_m2 < (cut['C'] ?? 180)) return 'C';
if (ep_conso_5_usages_m2 < (cut['D'] ?? 250)) return 'D';
const zc = enums.zone_climatique[zc_id];
if (['h1b', 'h1c', 'h2d'].includes(zc) && ca === 'supérieur à 800m') {
if (ep_conso_5_usages_m2 < (cut['E'] ?? 390)) return 'E';
if (ep_conso_5_usages_m2 < (cut['F'] ?? 500)) return 'F';
} else {
if (ep_conso_5_usages_m2 < (cut['E'] ?? 330)) return 'E';
if (ep_conso_5_usages_m2 < (cut['F'] ?? 420)) return 'F';
}
return 'G';
}
export function classe_emission_ges(emission_ges_5_usages_m2, zc_id, ca_id, Sh) {
const ca = enums.classe_altitude[ca_id];
const cut = tvs.ges_class_limit[ca][Math.round(Sh)] ?? [];
if (emission_ges_5_usages_m2 == null) return null;
if (emission_ges_5_usages_m2 < (cut['A'] ?? 6)) return 'A';
if (emission_ges_5_usages_m2 < (cut['B'] ?? 11)) return 'B';
if (emission_ges_5_usages_m2 < (cut['C'] ?? 30)) return 'C';
if (emission_ges_5_usages_m2 < (cut['D'] ?? 50)) return 'D';
const zc = enums.zone_climatique[zc_id];
if (['h1b', 'h1c', 'h2d'].includes(zc) && ca === 'supérieur à 800m') {
if (emission_ges_5_usages_m2 < (cut['E'] ?? 80)) return 'E';
if (emission_ges_5_usages_m2 < (cut['F'] ?? 110)) return 'F';
} else {
if (emission_ges_5_usages_m2 < (cut['E'] ?? 70)) return 'E';
if (emission_ges_5_usages_m2 < (cut['F'] ?? 100)) return 'F';
}
return 'G';
}
/**
Calcul de la consommation globale d'ECS
* @param gen_ecs {Generateur_ecs_collection}
* @param field {string}
* @param coef {number}
* @param prorataECS {number}
* @param prefix {string}
* @returns {number}
*/
function getEcsConso(gen_ecs, field, coef, prorataECS, prefix) {
return gen_ecs.reduce((acc, gen_ecs) => {
const conso = gen_ecs.donnee_intermediaire[field];
const typeEnergie = getTypeEnergie(gen_ecs.donnee_entree, 'ecs');
let coeffConsoEcs = { ...coef };
if (prefix === 'emission_ges') {
coeffConsoEcs[typeEnergie] = gen_ecs.donnee_utilisateur.coeffEmissionGes;
}
return (
acc +
getConso(coeffConsoEcs, typeEnergie, conso) *
(gen_ecs.donnee_entree.cle_repartition_ecs || prorataECS)
);
}, 0);
}
/**
* Calcul de la consommation globale de chauffage
* @param gen_ch {Generateur_chauffage_collection}
* @param field {string}
* @param coef {number}
* @param prorataChauffage {number}
* @param prefix {string}
* @returns {number}
*/
function getChauffageConso(gen_ch, field, coef, prorataChauffage, prefix) {
return gen_ch.reduce((acc, gen_ch) => {
const conso = gen_ch.donnee_intermediaire[field];
const typeEnergie = getTypeEnergie(gen_ch.donnee_entree, 'ch');
// La clé de répartition n'est utilisée que dans le cadre des chauffages collectifs
const repartition =
gen_ch.donnee_entree.enum_type_installation_id !== '1'
? gen_ch.donnee_entree.cle_repartition_ch || prorataChauffage
: prorataChauffage;
let coeffConsoChauffage = { ...coef };
if (prefix === 'emission_ges') {
coeffConsoChauffage[typeEnergie] = gen_ch.donnee_utilisateur.coeffEmissionGes;
}
return acc + getConso(coeffConsoChauffage, typeEnergie, conso) * repartition;
}, 0);
}
function calc_conso_pond(
Sh,
zc_id,
vt_list,
gen_ch,
gen_ecs,
fr_list,
prefix,
coef,
prorataECS,
prorataChauffage
) {
const ret = {};
ret.auxiliaire_ventilation = vt_list.reduce((acc, vt) => {
let conso = vt.donnee_intermediaire.conso_auxiliaire_ventilation || 0;
if (vt.donnee_entree.cle_repartition_ventilation) {
conso *= vt.donnee_entree.cle_repartition_ventilation;
}
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
const conso_eclairage = calc_conso_eclairage(zc_id) * Sh;
ret.eclairage = getConso(coef, 'électricité éclairage', conso_eclairage);
// aux ch
ret.auxiliaire_generation_ch = gen_ch.reduce((acc, gen_ch) => {
const conso = gen_ch.donnee_intermediaire.conso_auxiliaire_generation_ch || 0;
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
ret.auxiliaire_generation_ch_depensier = gen_ch.reduce((acc, gen_ch) => {
const conso = gen_ch.donnee_intermediaire.conso_auxiliaire_generation_ch_depensier || 0;
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
ret.auxiliaire_distribution_ch = gen_ch.reduce((acc, gen_ch) => {
let conso = gen_ch.donnee_intermediaire.conso_auxiliaire_distribution_ch || 0;
/**
* enum_methode_calcul_conso_id
* 2 : 'installation collective rapportée à un logement : cas générateur à combustion virtuel ou ecs collective virtuelle'
*/
if (
['2', '4'].includes(gen_ch.donnee_entree.enum_methode_calcul_conso_id) &&
gen_ch.donnee_entree.cle_repartition_ch
) {
conso *= gen_ch.donnee_entree.cle_repartition_ch;
}
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
ret.ch = getChauffageConso(gen_ch, 'conso_ch', coef, prorataChauffage, prefix);
ret.ch_depensier = getChauffageConso(
gen_ch,
'conso_ch_depensier',
coef,
prorataChauffage,
prefix
);
ret.auxiliaire_generation_ecs = gen_ecs.reduce((acc, gen_ecs) => {
const conso = gen_ecs.donnee_intermediaire.conso_auxiliaire_generation_ecs || 0;
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
ret.auxiliaire_generation_ecs_depensier = gen_ecs.reduce((acc, gen_ecs) => {
const conso = gen_ecs.donnee_intermediaire.conso_auxiliaire_generation_ecs_depensier || 0;
return acc + getConso(coef, 'électricité auxiliaire', conso);
}, 0);
ret.auxiliaire_distribution_ecs = 0;
ret.ecs = getEcsConso(gen_ecs, 'conso_ecs', coef, prorataECS, prefix);
ret.ecs_depensier = getEcsConso(gen_ecs, 'conso_ecs_depensier', coef, prorataECS, prefix);
ret.fr = fr_list.reduce((acc, fr) => {
const conso = fr.donnee_intermediaire.conso_fr;
const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');
return acc + getConso(coef, typeEnergie, conso);
}, 0);
ret.fr_depensier = fr_list.reduce((acc, fr) => {
const conso = fr.donnee_intermediaire.conso_fr_depensier;
const typeEnergie = getTypeEnergie(fr.donnee_entree, 'fr');
return acc + getConso(coef, typeEnergie, conso);
}, 0);
let tot_aux;
if (prefix === 'cout') tot_aux = 'total_auxiliaire';
else tot_aux = 'totale_auxiliaire';
ret[tot_aux] =
ret.auxiliaire_ventilation +
ret.auxiliaire_generation_ch +
ret.auxiliaire_generation_ecs +
ret.auxiliaire_distribution_ch +
ret.auxiliaire_distribution_ecs;
ret['5_usages'] = ret.ch + ret.ecs + ret.fr + ret[tot_aux] + ret.eclairage;
if (prefix !== 'cout') ret['5_usages_m2'] = Math.floor(ret['5_usages'] / Sh);
// add prefix_ to all ret keys
Object.keys(ret).forEach((key) => {
ret[`${prefix}_${key}`] = ret[key];
delete ret[key];
});
return ret;
}
/**
* Retourne le type d'énergie utilisé.
* 1 - Electricité par défaut si la donnée n'est pas définie
* @param donneeEntree {Donnee_entree}
* @param suffix {string} Suffix à ajouter au type électricité
* @return {string}
*/
function getTypeEnergie(donneeEntree, suffix) {
let type_energie = enums.type_energie[donneeEntree.enum_type_energie_id || 1];
if (type_energie === 'électricité') type_energie = `électricité ${suffix}`;
return type_energie;
}