Skip to content

Commit

Permalink
Merge pull request jzck#276 from RedFroggy/274MultipleCombustionGen
Browse files Browse the repository at this point in the history
fix(fix-274): Conso CH for multiple combustion generators
  • Loading branch information
jgavignet authored Dec 4, 2024
2 parents 00657b7 + 803ab87 commit ab86cc7
Show file tree
Hide file tree
Showing 9 changed files with 2,765 additions and 95 deletions.
7 changes: 3 additions & 4 deletions src/13.2_generateur_combustion.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { bug_for_bug_compat, tv, tvColumnLines } from './utils.js';
import { bug_for_bug_compat, convertExpression, tv, tvColumnLines } from './utils.js';
import enums from './enums.js';
import { updateGenerateurBouilleurs } from './13.2_generateur_combustion_bouilleur.js';
import { updateGenerateurChaudieres } from './13.2_generateur_combustion_chaudiere.js';
Expand All @@ -15,7 +15,7 @@ function criterePn(Pn, matcher) {
critere_list = critere_list.map((c) => c.replace('≤', '<='));
// find critere in critere_list that is true when executed
for (const critere of critere_list) {
if (eval(`let Pn=${Pn} ;${critere}`)) {
if (eval(`let Pn=${Pn} ;${convertExpression(critere)}`)) {
ret = critere.replace('<=', '≤');
break;
}
Expand Down Expand Up @@ -111,7 +111,7 @@ export function tv_generateur_combustion(dpe, di, de, type, GV, tbase, methodeSa

let matcher = {};
matcher[typeGenerateurKey] = enumTypeGenerateurId;
matcher.critere_pn = criterePn(di.pn / 1000, matcher);
matcher.critere_pn = criterePn(di.pn / (de.ratio_virtualisation * 1000), matcher);

row = tv('generateur_combustion', matcher);

Expand Down Expand Up @@ -150,7 +150,6 @@ export function tv_generateur_combustion(dpe, di, de, type, GV, tbase, methodeSa
}

de.tv_generateur_combustion_id = Number(row.tv_generateur_combustion_id);
if (Number(row.pn)) di.pn = Number(row.pn) * 1000;

const E = E_tab[de.presence_ventouse];
const F = F_tab[de.presence_ventouse];
Expand Down
39 changes: 5 additions & 34 deletions src/13.2_generateur_combustion_ch.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
import enums from './enums.js';
import {
bug_for_bug_compat,
requestInput,
requestInputID,
Tbase,
tv,
tvColumnIDs
} from './utils.js';
import { tv_generateur_combustion } from './13.2_generateur_combustion.js';
import { bug_for_bug_compat, requestInput, requestInputID, tv } from './utils.js';

const coef_pond = {
0.05: 0.1,
Expand Down Expand Up @@ -40,7 +32,7 @@ const K = {
'réseau de froid urbain': undefined
};

function tv_temp_fonc_30_100(di, de, du, em_ch, ac) {
export function tv_temp_fonc_30_100(di, de, du, em_ch, ac) {
for (const em of em_ch) {
const em_ch_de = em.donnee_entree;
const em_ch_du = em.donnee_utilisateur;
Expand Down Expand Up @@ -159,28 +151,7 @@ function Pcons(x, de, di, Cdimref) {
return Pfou(x, di, Cdimref) * (1 + QPx(x_final, de, di) / Px(x, di, Cdimref));
}

export function calc_generateur_combustion_ch(dpe, di, de, du, em_ch, GV, ca_id, zc_id, ac) {
const ca = enums.classe_altitude[ca_id];
const zc = enums.zone_climatique[zc_id];
const tbase = Tbase[ca][zc.slice(0, 2)];

const methodeSaisie = parseInt(de.enum_methode_saisie_carac_sys_id);
tv_generateur_combustion(dpe, di, de, 'ch', GV, tbase, methodeSaisie);

const type_gen_ch_list = tvColumnIDs('temp_fonc_30', 'type_generateur_ch');
if (type_gen_ch_list.includes(de.enum_type_generateur_ch_id)) {
/**
* Si la méthode de saisie n'est pas "Valeur forfaitaire" mais "caractéristiques saisies"
* Documentation 3CL : "Pour les installations récentes ou recommandées, les caractéristiques réelles des chaudières présentées sur les bases
* de données professionnelles peuvent être utilisées."
*
* 5 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0,temp_fonc_30,temp_fonc_100
*/
if (methodeSaisie !== 5 || !di.temp_fonc_30 || !di.temp_fonc_100) {
tv_temp_fonc_30_100(di, de, du, em_ch, ac);
}
}

export function calc_generateur_combustion_ch(dpe, di, de, du) {
if (bug_for_bug_compat) {
if (di.qp0 < 1) {
di.qp0 *= 1000;
Expand All @@ -195,8 +166,8 @@ export function calc_generateur_combustion_ch(dpe, di, de, du, em_ch, GV, ca_id,
di.pveil = 0;
}

const Cdimref = di.pn / (GV * (19 - tbase));
const Cdimref_dep = di.pn / (GV * (21 - tbase));
const Cdimref = du.cdimref || 0;
const Cdimref_dep = du.cdimrefDep || 0;
const Pmfou = Object.keys(coef_pond).reduce((acc, x) => acc + Pfou(x, di, Cdimref), 0);
const Pmcons = Object.keys(coef_pond).reduce((acc, x) => acc + Pcons(x, de, di, Cdimref), 0);
const Pmfou_dep = Object.keys(coef_pond).reduce((acc, x) => acc + Pfou(x, di, Cdimref_dep), 0);
Expand Down
147 changes: 116 additions & 31 deletions src/9_chauffage.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { requestInput, tv, tvColumnIDs } from './utils.js';
import { requestInput, Tbase, tv, tvColumnIDs } from './utils.js';
import { calc_emetteur_ch } from './9_emetteur_ch.js';
import {
calc_generateur_ch,
hasConsoForAuxDistribution,
type_generateur_ch
checkForGeneratorType,
hasConsoForAuxDistribution
} from './9_generateur_ch.js';
import { tv_generateur_combustion } from './13.2_generateur_combustion.js';
import { tv_temp_fonc_30_100 } from './13.2_generateur_combustion_ch.js';
import enums from './enums.js';

export default function calc_chauffage(
dpe,
Expand All @@ -25,6 +28,10 @@ export default function calc_chauffage(
const di = {};
const du = {};

const ca = enums.classe_altitude[ca_id];
const zc = enums.zone_climatique[zc_id];
const tbase = Tbase[ca][zc.slice(0, 2)];

di.besoin_ch = bch;
di.besoin_ch_depensier = bch_dep;

Expand All @@ -33,23 +40,65 @@ export default function calc_chauffage(
calc_emetteur_ch(em_ch, de, map_id, inertie_id);
});

const Fch = tv_ch_facteur_couverture_solaire(de, zc_id);
const cfg_id = requestInput(de, du, 'cfg_installation_ch');
const gen_ch = ch.generateur_chauffage_collection.generateur_chauffage;

gen_ch.forEach((gen) => {
const genChDe = gen.donnee_entree;
const genChDu = gen.donnee_utilisateur || {};
const genChDi = gen.donnee_intermediaire || {};

genChDe.ratio_virtualisation = de.ratio_virtualisation || 1;
genChDe.surface_chauffee = de.surface_chauffee || Sh;
genChDe.nombre_niveau_installation_ch = de.nombre_niveau_installation_ch || 1;
genChDe.fch = Fch || 0.5;

// Récupération du type de générateur
checkForGeneratorType(dpe, genChDe, genChDi, genChDu);

if (genChDu.isCombustionGenerator) {
const methodeSaisie = parseInt(genChDe.enum_methode_saisie_carac_sys_id);
tv_generateur_combustion(dpe, genChDi, genChDe, 'ch', GV, tbase, methodeSaisie);

const type_gen_ch_list = tvColumnIDs('temp_fonc_30', 'type_generateur_ch');
if (type_gen_ch_list.includes(genChDe.enum_type_generateur_ch_id)) {
/**
* Si la méthode de saisie n'est pas "Valeur forfaitaire" mais "caractéristiques saisies"
* Documentation 3CL : "Pour les installations récentes ou recommandées, les caractéristiques réelles des chaudières présentées sur les bases
* de données professionnelles peuvent être utilisées."
*
* 5 - caractéristiques saisies à partir de la plaque signalétique ou d'une documentation technique du système à combustion : pn, rpn,rpint,qp0,temp_fonc_30,temp_fonc_100
*/
if (methodeSaisie !== 5 || !genChDi.temp_fonc_30 || !genChDi.temp_fonc_100) {
tv_temp_fonc_30_100(genChDi, genChDe, genChDu, em_ch, ac);
}
}
}

gen.donnee_intermediaire = genChDi;
gen.donnee_utilisateur = genChDu;
gen.donnee_entree = genChDe;
});

/**
* 13.2.1.3 Cascade de deux générateurs à combustion
* Une puissance relative pour chaque générateur est calculée et appliquée à la conso globale de chauffage
* Seuls les générateurs en cascade sont concernés
*
* 9.1.4.3 Les pompes à chaleur hybrides
* Cas particulier des PAC hybrides avec répartition forfaitaire du besoin
* @type {number|number}
*/
const Pnominal = gen_ch.reduce((acc, gen) => acc + gen.donnee_intermediaire.pn, 0);
du.Pnominal = Pnominal;

const nbCascadeAndCombustion = gen_ch.filter(
(value) =>
isGenerateurCombustion(value) && Number.parseInt(de.enum_cfg_installation_ch_id) === 1
value.donnee_utilisateur.isCombustionGenerator &&
Number.parseInt(de.enum_cfg_installation_ch_id) === 1
).length;

const Fch = tv_ch_facteur_couverture_solaire(de, zc_id);

// Nombre de générateurs avec une consommation des auxiliaires de distribution
const nbGenWithAuxConsoDistribution = gen_ch.reduce((acc, gen) => {
if (hasConsoForAuxDistribution(gen.donnee_entree.enum_type_generateur_ch_id)) {
Expand All @@ -62,11 +111,6 @@ export default function calc_chauffage(
const prorataGenerateur =
nbCascadeAndCombustion > 1 ? gen.donnee_intermediaire.pn / Pnominal : 1;

gen.donnee_entree.ratio_virtualisation = de.ratio_virtualisation || 1;
gen.donnee_entree.surface_chauffee = de.surface_chauffee || Sh;
gen.donnee_entree.nombre_niveau_installation_ch = de.nombre_niveau_installation_ch || 1;
gen.donnee_entree.fch = Fch || 0.5;

calc_generateur_ch(
dpe,
gen,
Expand All @@ -80,11 +124,10 @@ export default function calc_chauffage(
hsp,
ca_id,
zc_id,
ac,
ilpa
);

// Si plusieurs générateurs de chauffage, la consommation des auxiliares est répartie sur chacun d'eux
// Si plusieurs générateurs de chauffage, la consommation des auxiliaires est répartie sur chacun d'eux
if (
gen.donnee_intermediaire.conso_auxiliaire_distribution_ch &&
nbGenWithAuxConsoDistribution > 0
Expand All @@ -103,24 +146,6 @@ export default function calc_chauffage(
ch.donnee_utilisateur = du;
}

/**
* Return true si le générateur est de type combustion
* @param gen_ch {GenerateurChauffageItem}
* @returns {boolean}
*/
function isGenerateurCombustion(gen_ch) {
const de = gen_ch.donnee_entree;
const di = gen_ch.donnee_intermediaire || {};
const du = gen_ch.donnee_utilisateur || {};

const usage_generateur = requestInput(de, du, 'usage_generateur');
const type_gen_ch_id = type_generateur_ch(di, de, du, usage_generateur);

const combustion_ids = tvColumnIDs('generateur_combustion', 'type_generateur_ch');

return combustion_ids.includes(type_gen_ch_id);
}

/**
* Retourne le facteur de couverture solaire pour les maisons avec chauffage solaire
* @param de {Donnee_entree}
Expand Down Expand Up @@ -148,3 +173,63 @@ function tv_ch_facteur_couverture_solaire(de, zc_id) {
return null;
}
}

/**
* 13.2.1.2 Présence d’un ou plusieurs générateurs à combustion indépendants
* Calcul du taux de charge cdimref et cdimrefDep pour chacun des générateurs
*
* @param installationChauffage {InstallationChauffageItem[]}
* @param GV {number} déperdition de l'enveloppe
* @param zcId {string} id de la zone climatique du bien
* @param caId {string} id de la classe d'altitude du bien
*/
export function tauxChargeForGenerator(installationChauffage, GV, caId, zcId) {
// Récupération des installations de chauffage avec générateur à combustion
const installChauffageWithCombustion = [];
installationChauffage.forEach((ch) => {
const gen_ch = ch.generateur_chauffage_collection.generateur_chauffage;

const genCombustion = gen_ch.reduce((acc, gen) => {
if (gen.donnee_utilisateur.isCombustionGenerator) {
acc.push(gen);
}

return acc;
}, []);

if (genCombustion.length) {
ch.donnee_utilisateur.genCombustion = genCombustion;
installChauffageWithCombustion.push(ch);
}
});

const ca = enums.classe_altitude[caId];
const zc = enums.zone_climatique[zcId];
const tbase = Tbase[ca][zc.slice(0, 2)];

// Pour N générateurs à combustion, puissance totale de tous les générateurs
const Pn = installChauffageWithCombustion.reduce(
(acc, gen) => acc + gen.donnee_utilisateur.Pnominal,
0
);

// Pour une seule installation avec des générateurs à combustion
installChauffageWithCombustion.forEach((installCh) => {
(installCh.donnee_utilisateur.genCombustion || []).forEach((gen) => {
let cdimref;
let cdimrefDep;

if (installChauffageWithCombustion.length > 1) {
// Plusieurs installations indépendantes de chauffage avec générateur à combustion
cdimref = Pn / (GV * (19 - tbase));
cdimrefDep = Pn / (GV * (21 - tbase));
} else {
// Pour une seule installation avec des générateurs à combustion
cdimref = gen.donnee_intermediaire.pn / (GV * (19 - tbase));
cdimrefDep = gen.donnee_intermediaire.pn / (GV * (21 - tbase));
}
gen.donnee_utilisateur.cdimref = cdimref;
gen.donnee_utilisateur.cdimrefDep = cdimrefDep;
});
});
}
57 changes: 34 additions & 23 deletions src/9_generateur_ch.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,26 +78,14 @@ export function type_generateur_ch(di, de, du, usage_generateur) {
return type_generateur;
}

export function calc_generateur_ch(
dpe,
gen_ch,
_pos,
em_ch,
cfg_ch,
bch,
bch_dep,
GV,
Sh,
hsp,
ca_id,
zc_id,
ac,
ilpa
) {
const de = gen_ch.donnee_entree;
const du = gen_ch.donnee_utilisateur || {};
const di = gen_ch.donnee_intermediaire || {};

/**
* Récupération du type de générateur
* @param dpe {FullDpe}
* @param de {Donnee_entree}
* @param di {Donnee_intermediaire}
* @param du {Object}
*/
export function checkForGeneratorType(dpe, de, di, du) {
const combustion_ids = tvColumnIDs('generateur_combustion', 'type_generateur_ch');
const pac_ids = tvColumnIDs('scop', 'type_generateur_ch');

Expand Down Expand Up @@ -154,7 +142,30 @@ export function calc_generateur_ch(
}
}

if (isPacGenerator) {
du.isPacGenerator = isPacGenerator;
du.isCombustionGenerator = isCombustionGenerator;
}

export function calc_generateur_ch(
dpe,
gen_ch,
_pos,
em_ch,
cfg_ch,
bch,
bch_dep,
GV,
Sh,
hsp,
ca_id,
zc_id,
ilpa
) {
const de = gen_ch.donnee_entree;
const du = gen_ch.donnee_utilisateur || {};
const di = gen_ch.donnee_intermediaire || {};

if (du.isPacGenerator) {
let em;

// Si un seul émetteur de chauffage décrit, on considère que cet émetteur est relié au générateur de chauffage
Expand All @@ -176,8 +187,8 @@ export function calc_generateur_ch(
di.rg = di.scop || di.cop;
di.rg_dep = di.scop || di.cop;
}
} else if (isCombustionGenerator) {
calc_generateur_combustion_ch(dpe, di, de, du, em_ch, GV, ca_id, zc_id, ac);
} else if (du.isCombustionGenerator) {
calc_generateur_combustion_ch(dpe, di, de, du);
} else {
tv_rendement_generation(di, de, du);
}
Expand Down
Loading

0 comments on commit ab86cc7

Please sign in to comment.