@jzck/open3cl
Version:
Open Source 3CL-DPE engine
464 lines (415 loc) • 17.2 kB
JavaScript
import enums from './enums.js';
import { tv, requestInput, compareReferences, bug_for_bug_compat } from './utils.js';
function defaultValue(type_liaison, pt_di, de) {
if (pt_di.k === 0) {
return 0;
}
const row = tv('pont_thermique', {
tv_pont_thermique_id: de.tv_pont_thermique_id
});
const k = row ? row.k : pt_di.k;
/**
* Si la valeur décrite par tv_pont_thermique_id est différente de celle donnée en valeur intermédiaire
* et différente de la moitié de celle-ci (prise en compte du facteur pourcentage_valeur_pont_thermique = 0.5 dans les cas où le
* pt ne sépare pas 2 pièces du même lot) alors on prend la valeur intermédiaire saisie
*/
if (parseFloat(pt_di.k) !== parseFloat(k) && parseFloat(pt_di.k) !== parseFloat(k) / 2) {
console.error(
`Incohérence pour le pont thermique ${de.description}, décrit avec tv_pont_thermique_id = ${de.tv_pont_thermique_id} mais k = ${pt_di.k}.
tv_pont_thermique_id est ignoré, la valeur k = ${pt_di.k} est conservée`
);
return pourcentageValeurPontThermique(type_liaison, de, pt_di.k, pt_di);
}
return pourcentageValeurPontThermique(type_liaison, de, k, pt_di);
}
function tv_k(pt_di, di, de, du, pc_id, logement) {
const enveloppe = logement.enveloppe;
const mur_list = enveloppe.mur_collection.mur || [];
const pb_list = enveloppe.plancher_bas_collection.plancher_bas || [];
const ph_list = enveloppe.plancher_haut_collection.plancher_haut || [];
const bv_list = enveloppe.baie_vitree_collection.baie_vitree || [];
const porte_list = enveloppe.porte_collection.porte || [];
const type_liaison = requestInput(de, du, 'type_liaison');
if (!de.reference_1) {
console.warn(`BUG: pas de reference pour le pont thermique ${de.description}...`);
// on trouve les references grace a la description
const desc = de.description;
let desc_1, desc_2;
if (desc?.match(/(.+) \/ (.+)/)) {
desc_1 = desc.match(/(.+) \/ (.+)/)[1];
desc_2 = desc.match(/(.+) \/ (.+)/)[2];
} else if (desc?.match(/(.+)-(.+)/)) {
desc_1 = desc.match(/(.+)-(.+)/)[1];
desc_2 = desc.match(/(.+)-(.+)/)[2];
} else {
di.k = defaultValue(type_liaison, pt_di, de);
console.error(
`BUG: description '${desc}' non reconnue pour le pont thermique.
La valeur de k est prise dans les données intermédiaires du DPE`
);
return;
}
let ptMur = mur_list.find(
(mur) =>
mur.donnee_entree.description?.includes(desc_1) ||
mur.donnee_entree.description?.includes(desc_2)
);
if (ptMur) {
de.reference_1 = ptMur.donnee_entree.reference;
} else {
di.k = defaultValue(type_liaison, pt_di, de);
console.error(
`BUG: descriptions '${desc_1}' ou '${desc_2}' du pont thermique non reconnue dans les descriptions des murs.
La valeur de k est prise dans les données intermédiaires du DPE`
);
return;
}
let list_2;
switch (type_liaison) {
case 'refend / mur':
list_2 = null;
break;
case 'plancher intermédiaire lourd / mur':
// TODO
console.warn(`Pont thermique ${type_liaison} non supporté`);
break;
case 'plancher bas / mur':
case 'plancher haut lourd / mur':
list_2 = pb_list.concat(ph_list);
break;
case 'menuiserie / mur':
list_2 = bv_list.concat(porte_list);
break;
}
if (list_2) {
ptMur = list_2.find(
(men) =>
men.donnee_entree.description?.includes(desc_2) ||
men.donnee_entree.description?.includes(desc_1)
);
if (ptMur) {
de.reference_2 = ptMur.donnee_entree.reference;
} else {
di.k = defaultValue(type_liaison, pt_di, de);
console.error(
`BUG: descriptions '${desc_1}' ou '${desc_2}' du pont thermique non reconnue dans '${type_liaison}'.
La valeur de k est prise dans les données intermédiaires du DPE`
);
return;
}
}
}
const mur = mur_list.find(
(mur) =>
compareReferences(mur.donnee_entree.reference, de.reference_1) ||
compareReferences(mur.donnee_entree.reference, de.reference_2)
);
const matcher = {
enum_type_liaison_id: de.enum_type_liaison_id
};
const pc = enums.periode_construction[pc_id];
let type_isolation_mur;
if (mur) {
/**
* 3.4 Calcul des déperditions par les ponts thermiques
* Les ponts thermiques des parois au niveau des circulations communes ne sont pas pris en compte.
* 14 - Circulation sans ouverture directe sur l'extérieur
* 15 - Circulation avec ouverture directe sur l'extérieur
* 16 - Circulation avec bouche ou gaine de désenfumage ouverte en permanence
* 17 - Hall d'entrée avec dispositif de fermeture automatique
* 18 - Hall d'entrée sans dispositif de fermeture automatique
* 22 - Local non déperditif ( local à usage d'habitation chauffé)
*/
if (
mur &&
['14', '15', '16', '17', '18', '22'].includes(mur.donnee_entree.enum_type_adjacence_id)
) {
/**
* Certains ponts thermiques de type 'plancher bas / mur' ou 'plancher haut lourd / mur', bien que sur des circulations doivent être pris en compte
* Certaines configurations du logement n'étant pas définissable, on doit se baser sur les données décrites dans le DPE
*/
if (pt_di.k === 0) {
di.k = 0;
return;
}
}
type_isolation_mur = requestInput(mur.donnee_entree, mur.donnee_utilisateur, 'type_isolation');
const pi = requestInput(mur.donnee_entree, mur.donnee_utilisateur, 'periode_isolation') || pc;
if (type_isolation_mur.includes('inconnu')) {
if (['avant 1948', '1948-1974'].includes(pi)) type_isolation_mur = 'non isolé';
else type_isolation_mur = 'iti';
}
matcher.isolation_mur = `^${type_isolation_mur}$`;
} else {
matcher.isolation_mur = `^iti`;
}
switch (type_liaison) {
case 'plancher bas / mur':
case 'plancher haut lourd / mur': {
const plancher_list = ph_list.concat(pb_list);
const plancher = plancher_list.find(
(plancher) =>
compareReferences(plancher.donnee_entree.reference, de.reference_1) ||
compareReferences(plancher.donnee_entree.reference, de.reference_2)
);
if (!plancher) {
di.k = defaultValue(type_liaison, pt_di, de);
console.error(
`Impossible de trouver un plancher ayant pour référence '${de.reference_1}' ou '${de.reference_2}'.
La valeur de k est prise dans les données intermédiaires du DPE`
);
return;
}
/**
* 3.4.3 Plancher haut / mur
* Les ponts thermiques des planchers haut en structure légère sont négligés.
* type_plancher_haut
* enum_type_plancher_haut_id
* 9 - Plafond bois sur solives bois
* 10 - Plafond bois sous solives bois
*
* enum_materiaux_structure_mur_id
* 5 - Murs en pan de bois sans remplissage tout venant
* 6 - Murs en pan de bois avec remplissage tout venant
* 7 - Murs bois (rondin)
* 16 - Béton cellulaire avant 2013
* 18 - Murs en ossature bois avec isolant en remplissage ≥ 2006
* 24 - Murs en ossature bois avec isolant en remplissage 2001-2005
* 25 - Murs en ossature bois sans remplissage
* 26 - Murs en ossature bois avec isolant en remplissage <2001
* 27 - Murs en ossature bois avec remplissage tout venant
*/
if (
mur &&
type_liaison === 'plancher haut lourd / mur' &&
([9, 10].includes(parseInt(plancher.donnee_entree.enum_type_plancher_haut_id)) ||
[5, 6, 7, 16, 18, 24, 25, 26, 27].includes(
parseInt(mur.donnee_entree.enum_materiaux_structure_mur_id)
))
) {
di.k = 0;
return;
}
/**
* 3.4.1 Mur Plancher bas / mur
* Seuls les murs et planchers bas constitués d’un matériau lourd (béton, brique, …) sont considérés ici. Pour les autres
* cas ce pont thermique est pris nul.
* enum_type_plancher_bas_id
* 4 - Plancher entre solives bois avec ou sans remplissage
* 10 - Plancher bois sur solives bois
*
* enum_materiaux_structure_mur_id
* 5 - Murs en pan de bois sans remplissage tout venant
* 6 - Murs en pan de bois avec remplissage tout venant
* 7 - Murs bois (rondin)
* 16 - Béton cellulaire avant 2013
* 18 - Murs en ossature bois avec isolant en remplissage ≥ 2006
* 24 - Murs en ossature bois avec isolant en remplissage 2001-2005
* 25 - Murs en ossature bois sans remplissage
* 26 - Murs en ossature bois avec isolant en remplissage <2001
* 27 - Murs en ossature bois avec remplissage tout venant
*/
if (
mur &&
type_liaison === 'plancher bas / mur' &&
([4, 10].includes(parseInt(plancher.donnee_entree.enum_type_plancher_bas_id)) ||
[5, 6, 7, 16, 18, 24, 25, 26, 27].includes(
parseInt(mur.donnee_entree.enum_materiaux_structure_mur_id)
))
) {
di.k = 0;
return;
}
const isolation_plancher = requestInput(
plancher.donnee_entree,
plancher.donnee_utilisateur,
'type_isolation'
);
matcher.isolation_plancher = `^${isolation_plancher}$`;
if (isolation_plancher === 'inconnu') {
const type_adjacence_plancher = requestInput(
plancher.donnee_entree,
plancher.donnee_utilisateur,
'type_adjacence'
);
const pi =
requestInput(plancher.donnee_entree, plancher.donnee_utilisateur, 'periode_isolation') ||
pc;
let cutoff;
if (type_adjacence_plancher === 'terre-plein') {
cutoff = ['avant 1948', '1948-1974', '1975-1977', '1978-1982', '1983-1988', '1989-2000'];
} else cutoff = ['avant 1948', '1948-1974'];
if (cutoff.includes(pi)) matcher.isolation_plancher = 'non isolé';
else matcher.isolation_plancher = '^ite$';
} else if (isolation_plancher === "isolé mais type d'isolation inconnu") {
matcher.isolation_plancher = '^ite$';
}
break;
}
case 'plancher intermédiaire lourd / mur':
// TODO
console.warn(`Pont thermique ${type_liaison} non supporté`);
break;
case 'refend / mur':
break;
case 'menuiserie / mur': {
/**
* 3.4.5 Menuiserie / mur
* Les ponts thermiques avec les parois en structure bois (ossature bois, rondin de bois, pans de bois) sont négligés.
* enum_materiaux_structure_mur_id
* 5 - Murs en pan de bois sans remplissage tout venant
* 6 - Murs en pan de bois avec remplissage tout venant
* 7 - Murs bois (rondin)
* 18 - Murs en ossature bois avec isolant en remplissage ≥ 2006
* 24 - Murs en ossature bois avec isolant en remplissage 2001-2005
* 25 - Murs en ossature bois sans remplissage
* 26 - Murs en ossature bois avec isolant en remplissage <2001
* 27 - Murs en ossature bois avec remplissage tout venant
*/
if (
mur &&
['5', '6', '7', '18', '24', '25', '26', '27'].includes(
mur.donnee_entree.enum_materiaux_structure_mur_id
)
) {
di.k = 0;
return;
}
// Si isolation ITR, k = 0.2, pas besoin des informations de la fenêtre
if (type_isolation_mur === 'itr') {
break;
}
const menuiserie_list = bv_list.concat(porte_list);
const menuiserie = menuiserie_list.find(
(men) =>
compareReferences(men.donnee_entree.reference, de.reference_1) ||
compareReferences(men.donnee_entree.reference, de.reference_2)
);
if (!menuiserie) {
di.k = defaultValue(type_liaison, pt_di, de);
console.error(
`Impossible de trouver une menuiserie ayant pour référence '${de.reference_1}' ou '${de.reference_2}'.
La valeur de k est prise dans les données intermédiaires du DPE`
);
return;
}
const mde = menuiserie.donnee_entree;
const mdu = menuiserie.donnee_utilisateur;
let type_pose = requestInput(mde, mdu, 'type_pose');
/**
* Si le type de pose n'est pas connu, on va récupérer l'information grâce à tv_pont_thermique_id
*/
if (!type_pose) {
if (bug_for_bug_compat) {
const tvPontThermique = tv('pont_thermique', {
tv_pont_thermique_id: de.tv_pont_thermique_id
});
console.error(
`La menuiserie '${mde.description}' n'a pas de type de pose. Récupération de celui-ci à partir de tv_pont_thermique_id`
);
if (tvPontThermique) {
type_pose = tvPontThermique.type_pose;
} else {
type_pose = 'tunnel';
}
} else {
type_pose = 'tunnel';
}
}
if (type_pose.includes('sans objet')) {
type_pose = 'tunnel';
}
matcher.type_pose = type_pose;
matcher.presence_retour_isolation = requestInput(
mde,
mdu,
'presence_retour_isolation',
'bool'
);
if (bug_for_bug_compat) {
// Certains logiciels n'utilisent le boolean presence_retour_isolation de la même manière
// 0 = oui pour certains, 1 = oui pour d'autres
const tvPontThermique = tv('pont_thermique', {
tv_pont_thermique_id: de.tv_pont_thermique_id
});
if (
tvPontThermique &&
parseInt(matcher.presence_retour_isolation) !==
parseInt(tvPontThermique.presence_retour_isolation)
) {
matcher.presence_retour_isolation = parseInt(tvPontThermique.presence_retour_isolation);
}
}
matcher.largeur_dormant = requestInput(mde, mdu, 'largeur_dormant', 'float');
}
}
const row = tv('pont_thermique', matcher);
if (row) {
di.k = Number(row.k);
de.tv_pont_thermique_id = Number(row.tv_pont_thermique_id);
pourcentageValeurPontThermique(type_liaison, de, di, pt_di);
} else {
console.error('!! pas de valeur forfaitaire trouvée pour pont_thermique (k) !!');
}
}
/**
* Calcul du facteur de prise en compte du pont thermique
*
* 3.4.4 Refend / mur
* Lorsque le refend ne sépare pas deux volumes du même lot faisant l’objet du DPE, il faut prendre en compte dans les
* calculs seulement la moitié de la valeur tabulée ci-dessus.
*
* 3.4.2 Plancher intermédiaire / mur
* Lorsque le plancher intermédiaire ne sépare pas deux niveaux du lot faisant l’objet du DPE, il faut prendre en compte
* dans les calculs seulement la moitié de la valeur tabulée ci-dessus
*
* Par défaut on prend 0.5 si la valeur n'est pas spécifiée, qu'il n'y a qu'un seul étage au logement.
* Si la valeur k calculée est égale au à celle spécifiée, le facteur est déjà pris en compte
*
* @param type_liaison {string} type de liaison du pont thermique en cours d'étude
* @param de {Donnee_entree} données d'entrée du pont thermique en cours d'étude
* @param k {string} valeur calculée pour k
* @param pt_di {Donnee_intermediaire} données intermédiaires du pont thermique en cours d'étude
*/
function pourcentageValeurPontThermique(type_liaison, de, k, pt_di) {
if (
!de.pourcentage_valeur_pont_thermique &&
(type_liaison === 'refend / mur' || type_liaison === 'plancher intermédiaire lourd / mur') &&
(parseFloat(k) !== parseFloat(pt_di.k) || pt_di.k > 1)
) {
de.pourcentage_valeur_pont_thermique = 0.5;
console.warn(
`Le pont thermique ${de.description} n'a aucune valeur pour pourcentage_valeur_pont_thermique.
Le bien n'ayant qu'un seul étage, on prend 0.5 dans la suite du calcul car ce pont thermique ne sépare pas deux niveaux du lot`
);
}
return k;
}
export default function calc_pont_thermique(pt, pc_id, logement) {
const de = pt.donnee_entree;
const di = {};
const du = {};
const methode_saisie_pont_thermique = parseInt(de.enum_methode_saisie_pont_thermique_id);
/**
* Si la valeur de k est directement saisie, prendre cette valeur
* enum_methode_saisie_pont_thermique_id
* 1 - valeur forfaitaire
* 2 - valeur justifiée saisie à partir des documents justificatifs autorisés
* 3 - saisie direct k depuis rset/rsee( etude rt2012/re2020)
*/
if (methode_saisie_pont_thermique === 1) {
tv_k(pt.donnee_intermediaire, di, de, du, pc_id, logement);
} else if (methode_saisie_pont_thermique === 2 || methode_saisie_pont_thermique === 3) {
if (de.k_saisi) {
di.k = de.k_saisi;
} else {
console.error(
`Aucune valeur de k_saisi pour le pont thermique '${pt.donnee_entree.reference}' alors que la donnée est saisie`
);
}
} else {
console.error('methode_saisie_pont_thermique non reconnu:' + methode_saisie_pont_thermique);
}
pt.donnee_utilisateur = du;
pt.donnee_intermediaire = di;
}