@open3cl/engine
Version:
Open Source 3CL-DPE engine
216 lines (195 loc) • 6.76 kB
JavaScript
import { inject } from 'dioma';
import { PRECISION } from '../../constants.js';
import { DeperditionService } from '../deperdition.service.js';
import { TvStore } from '../../../../dpe/infrastructure/tv.store.js';
/**
* Calcul des déperditions de l’enveloppe GV
* Chapitre 3.2.2 Calcul des planchers bas
*
* Méthode de calcul 3CL-DPE 2021
* Octobre 2021
* @see consolide_anne…arrete_du_31_03_2021_relatif_aux_methodes_et_procedures_applicables.pdf
*/
export class DeperditionPlancherBasService extends DeperditionService {
/**
* @param tvStore {TvStore}
*/
constructor(tvStore = inject(TvStore)) {
super(tvStore);
}
/**
* @param ctx {Contexte}
* @param pbDE {PlancherBasDE}
* @param plancherBas {PlancherBas[]}
* @return {PlancherBasDI}
*/
execute(ctx, pbDE, plancherBas) {
const upb0 = this.#upb0(pbDE);
const upb = this.#upb(pbDE, upb0, ctx);
const upb_final = this.#upbFinal(pbDE, upb, ctx, plancherBas);
const b = this.b({
enumTypeAdjacenceId: pbDE.enum_type_adjacence_id,
surfaceAiu: pbDE.surface_aiu,
surfaceAue: pbDE.surface_aue,
enumCfgIsolationLncId: pbDE.enum_cfg_isolation_lnc_id,
zoneClimatique: ctx.zoneClimatique.value
});
/** @type {PlancherBasDI} */
return { upb0, upb, upb_final, b };
}
/**
* @param pbDE {PlancherBasDE}
* @param upb0 {number}
* @param ctx {Contexte}
* @return {number|undefined}
*/
#upb(pbDE, upb0, ctx) {
// On determine upb_nu (soit upb0 soit 2 comme valeur minimale forfaitaire)
const upbNu = Math.min(upb0, 2);
const enumPeriodeIsolationId = this.getEnumPeriodeIsolationId(
pbDE.enum_periode_isolation_id,
ctx
);
// Selon l'isolation, on applique un calcul au upb nu pour simuler son isolation
let upb;
switch (pbDE.enum_methode_saisie_u_id) {
case '1': // non isolé
upb = upbNu;
break;
case '2': // isolation inconnue (table forfaitaire)
case '7': // année d'isolation différente de l'année de construction
case '8': // année de construction saisie
upb = Math.min(
upbNu,
this.tvStore.getUpb(enumPeriodeIsolationId, ctx.zoneClimatique.id, ctx.effetJoule)
);
break;
case '3': // epaisseur isolation saisie justifiée par mesure ou observation
case '4': // epaisseur isolation saisie (en cm)
upb = 1 / (1 / upbNu + (pbDE.epaisseur_isolation * 0.01) / 0.042);
break;
case '5':
case '6': // resistance isolation saisie
upb = 1 / (1 / upbNu + pbDE.resistance_isolation);
break;
default: // saisie direct de la valeur de u
upb = pbDE.upb_saisi;
break;
}
return Math.round(parseFloat(upb) * PRECISION) / PRECISION;
}
/**
* @param pbDE {PlancherBasDE}
* @return {number|undefined}
*/
#upb0(pbDE) {
let upb0;
switch (pbDE.enum_methode_saisie_u0_id) {
case '1': // 'type de paroi inconnu (valeur par défaut)'
case '2': // 'déterminé selon le matériau et épaisseur à partir de la table de valeur forfaitaire'
upb0 = this.tvStore.getUpb0(pbDE.enum_type_plancher_bas_id);
break;
case '5': // 'u0 non saisi car le u est saisi connu et justifié.'
return;
default: // Valeur saisie
return pbDE.upb0_saisi;
}
return upb0;
}
/**
* Pour les vides sanitaires, les sous-sol non chauffés et terre-plein, le calcul des déperditions se fait avec un coefficient
* Ue en remplacement de Upb.
*
* @param pbDE {PlancherBasDE}
* @param upb {number}
* @param ctx {Contexte}
* @param plancherBas {PlancherBas[]}
* @return {number|undefined}
*/
#upbFinal(pbDE, upb, ctx, plancherBas) {
if (pbDE.calcul_ue === 1) {
return pbDE.ue;
}
/**
* 3 - vide sanitaire
* 5 - terre-plein
* 6 - sous-sol non chauffé
*/
if (!['3', '5', '6'].includes(pbDE.enum_type_adjacence_id)) {
return upb;
}
/**
* La surface Ue est la surface de tous les planchers bas ayant le même type d'adjacence
* Le périmètre Ue est le périmètre de tous les planchers bas ayant le même type d'adjacence
*/
const { surfaceUe, perimetreUe } = plancherBas
.filter(
(plancherBas) =>
pbDE.enum_type_adjacence_id === plancherBas.donnee_entree.enum_type_adjacence_id
)
.reduce(
(acc, plancherBas) => {
acc.surfaceUe +=
plancherBas.donnee_entree.surface_ue || plancherBas.donnee_entree.surface_paroi_opaque;
acc.perimetreUe += plancherBas.donnee_entree.perimetre_ue || 0;
return acc;
},
{ surfaceUe: 0, perimetreUe: 0 }
);
const available2sp = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20];
let dsp = perimetreUe ? Math.round((2 * surfaceUe) / perimetreUe) : 1;
// Recherche de la valeur la plus proche dans les valeurs disponibles
dsp = available2sp.reduce((prev, curr) => {
return Math.abs(curr - dsp) < Math.abs(prev - dsp) ? curr : prev;
});
const upbFinal = this.tvStore.getUeByUpd(
pbDE.enum_type_adjacence_id,
ctx.enumPeriodeConstructionId,
dsp,
upb
);
return Math.round(parseFloat(upbFinal) * PRECISION) / PRECISION;
}
/**
* Retourner le type d'isolation du plancher
* Si isolation inconnue :
* - Les planchers sur terre-plein sont considérés non isolés avant 2001 et isolés par l’extérieur (en sous-face) à partir de 2001
* - Les autres planchers sont considérés isolés par l’extérieur
*
* @param ctx {Contexte}
* @param plancherBasDE {PlancherBasDE}
* @return {number}
*/
typeIsolation(ctx, plancherBasDE) {
const typeIsolation = parseInt(plancherBasDE.enum_type_isolation_id);
// Type d'isolation inconnu
if (typeIsolation === 1) {
const typeAdjacence = parseInt(plancherBasDE.enum_type_adjacence_id);
const periodeIsolation =
parseInt(plancherBasDE.enum_periode_isolation_id) ||
parseInt(ctx.enumPeriodeConstructionId);
// Plancher sur terre-plein
if (typeAdjacence === 5) {
// Année isolation / construction < 2001
if (periodeIsolation < 7) {
// Non isolé
return 2;
} else {
// Isolation ITE
return 4;
}
} else {
// Année isolation / construction < 1975
if (periodeIsolation < 3) {
// Non isolé
return 2;
} else {
// Isolation ITE
return 4;
}
}
}
// Isolation ITE si "isolé mais type d'isolation inconnu"
return typeIsolation === 9 ? 4 : typeIsolation;
}
}