@open3cl/engine
Version: 
Open Source 3CL-DPE engine
283 lines (246 loc) • 9.55 kB
JavaScript
import enums from './enums.js';
import { requestInput, requestInputID, tv, tvColumnIDs } from './utils.js';
import { conso_aux_distribution_ch, conso_aux_gen } from './15_conso_aux.js';
import { conso_ch } from './9_conso_ch.js';
import { calc_generateur_combustion_ch } from './13.2_generateur_combustion_ch.js';
import { scopOrCop } from './12.4_pac.js';
import { updateGenerateurCombustion } from './13.2_generateur_combustion.js';
const ENUM_MATERIAUX_STRUCTURE_MUR_ANCIEN_IDS = ['2', '3', '4', '6', '8', '9', '14', '21'];
const ENUM_CLASSES_INERTIE_LOURDES_IDS = ['1', '2'];
function pertes_gen_ch(Bch_hp_j, pn) {
  return (1.3 * Bch_hp_j) / (0.3 * pn);
}
function pertes_gen_ecs(nrefj) {
  return (nrefj * 1790) / 8760;
}
export function calc_Qrec_gen_j(gen_ch, nrefj, Bch_hp_j) {
  const de = gen_ch.donnee_entree;
  const du = gen_ch.donnee_utilisateur || {};
  const di = gen_ch.donnee_intermediaire;
  if (de.position_volume_chauffe === 0) return 0;
  const type_gen_ch = enums.type_generateur_ch[de.enum_type_generateur_ch_id];
  if (type_gen_ch.includes('générateur à air chaud')) return 0;
  let Cper;
  if (de.presence_ventouse === 1) Cper = 0.75;
  else Cper = 0.5;
  const usage_generateur = requestInput(de, du, 'usage_generateur');
  let Dperj;
  if (usage_generateur === 'chauffage') Dperj = Math.min(nrefj, pertes_gen_ch(Bch_hp_j, di.pn));
  else if (usage_generateur === 'ecs') Dperj = pertes_gen_ecs(nrefj);
  else if (usage_generateur === 'chauffage + ecs') {
    Dperj = Math.min(nrefj, pertes_gen_ch(Bch_hp_j, di.pn) + pertes_gen_ecs(nrefj));
  }
  gen_ch.donnee_utilisateur = du;
  return 0.48 * Cper * di.qp0 * Dperj || 0;
}
function tv_rendement_generation(di, de, du) {
  const matcher = {
    enum_type_generateur_ch_id: requestInputID(de, du, 'type_generateur_ch')
  };
  const row = tv('rendement_generation', matcher, de);
  if (row) {
    di.rendement_generation = Number(row.rg);
    di.rg = di.rendement_generation;
    di.rg_dep = di.rendement_generation;
    de.tv_rendement_generation_id = Number(row.tv_rendement_generation_id);
  } else {
    console.error('!! pas de valeur forfaitaire trouvée pour rendement_generation ch !!');
  }
}
export function type_generateur_ch(di, de, du, usage_generateur) {
  let type_generateur;
  if (usage_generateur === 'chauffage') {
    type_generateur = requestInputID(de, du, 'type_generateur_ch');
  } else if (usage_generateur === 'chauffage + ecs') {
    const generateur_ecs = enums.type_generateur_ecs;
    const generateur_ch = enums.type_generateur_ch;
    const generateurs_ch_ecs = Object.keys(generateur_ch).reduce((acc, key) => {
      const gen_ch = generateur_ch[key];
      if (Object.values(generateur_ecs).includes(gen_ch)) acc[key] = gen_ch;
      return acc;
    }, {});
    type_generateur = requestInputID(de, du, 'type_generateur_ch', Object.keys(generateurs_ch_ecs));
  } else {
    console.warn("!! usage_generateur n'est pas 'chauffage' ou 'chauffage + ecs' !!");
  }
  return type_generateur;
}
/**
 * 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');
  // Mise à jour du type de générateur si besoin
  updateGenerateurCombustion(dpe, de, 'ch');
  const usage_generateur = requestInput(de, du, 'usage_generateur');
  const type_gen_ch_id = type_generateur_ch(di, de, du, usage_generateur);
  let isPacGenerator = pac_ids.includes(type_gen_ch_id);
  let isCombustionGenerator = combustion_ids.includes(type_gen_ch_id);
  /**
   * Pour le type de chauffage 119 - système collectif par défaut en abscence d'information : chaudière fioul pénalisante,
   * détection en fonction des données d'entrées du type de générateur pour calculer les rendements de l'installation
   *
   * Si présence de tv_generateur_combustion_id dans les données d'entrée alors générateur à combustion
   * Si présence de tv_scop_id dans les données d'entrée alors générateur pompe à chaleur
   */
  if (type_gen_ch_id === '119') {
    isPacGenerator = false;
    isCombustionGenerator = false;
    if (de.tv_generateur_combustion_id) {
      const row = tv('generateur_combustion', {
        tv_generateur_combustion_id: de.tv_generateur_combustion_id
      });
      if (row) {
        // On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
        const typeGenerateurCh = row.enum_type_generateur_ch_id?.split('|');
        if (typeGenerateurCh && typeGenerateurCh.length) {
          de.enum_type_generateur_ch_id = typeGenerateurCh[0];
        }
      }
      isCombustionGenerator = true;
    } else if (de.tv_scop_id) {
      isPacGenerator = true;
    } else {
      const row = tv('rendement_generation', {
        tv_rendement_generation_id: de.tv_rendement_generation_id
      });
      if (row) {
        // On prend par défaut le premier type de générateur pour effectuer les calculs de rendement
        const typeGenerateurCh = row.enum_type_generateur_ch_id?.split('|');
        if (typeGenerateurCh && typeGenerateurCh.length) {
          de.enum_type_generateur_ch_id = typeGenerateurCh[0];
        }
      }
    }
  }
  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,
  tbase,
  besoin_ch_mois,
  s_chauffee_inst,
  gen_ch_list
) {
  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
    if (em_ch.length === 1) {
      em = em_ch[0];
    } else {
      const gen_lge_id = requestInputID(de, du, 'lien_generateur_emetteur');
      em = em_ch.find((em) => em.donnee_entree.enum_lien_generateur_emetteur_id === gen_lge_id);
    }
    if (em) {
      const ed_id = em.donnee_entree.enum_type_emission_distribution_id;
      scopOrCop(di, de, du, zc_id, ed_id, 'ch');
    } else {
      console.error(
        `Emetteur de chauffage non trouvé pour le générateur ${de.description}, les valeurs intermédiaires saisies sont prises en compte`
      );
      di.rg = di.scop || di.cop;
      di.rg_dep = di.scop || di.cop;
    }
  } else if (du.isCombustionGenerator) {
    calc_generateur_combustion_ch(dpe, di, de, du);
  } else {
    tv_rendement_generation(di, de, du);
  }
  conso_aux_gen(di, de, 'ch', bch, bch_dep, Sh);
  /**
   * 15 Calcul des consommations d’auxiliaires des installations de chauffage (Caux_ch) et d’ECS (Caux_ecs)
   */
  if (hasConsoForAuxDistribution(de.enum_type_generateur_ch_id)) {
    conso_aux_distribution_ch(em_ch, de, di, du, Sh, zc_id, ca_id, ilpa, GV);
  }
  const paroi_ancienne = isParoisAncienneInertieLourde(dpe);
  conso_ch(
    di,
    de,
    du,
    _pos,
    cfg_ch,
    em_ch,
    GV,
    Sh,
    hsp,
    bch,
    bch_dep,
    tbase,
    paroi_ancienne,
    ca_id,
    zc_id,
    besoin_ch_mois,
    s_chauffee_inst,
    gen_ch_list
  );
  gen_ch.donnee_intermediaire = di;
  gen_ch.donnee_utilisateur = du;
}
/**
 * 15 Calcul des consommations d’auxiliaires des installations de chauffage (Caux_ch) et d’ECS (Caux_ecs)
 *
 * Les consommations des auxiliaires de distribution de chauffage et d’ECS sont prises nulles pour les installations
 * individuelles en l’absence d’un circulateur externe au générateur. On exclut donc les générateurs suivants :
 *
 * >= 4 - exclusion des PAC air / air
 * >= 20 && <= 47 - exclusion des poêles
 * 53, 54 - exclusion des radiateurs gaz
 * >= 98 && <= 105 - exclusion des émetteurs à effet joule, radiateurs électriques, plafonds / planchers électriques
 *
 */
export function hasConsoForAuxDistribution(enum_type_generateur_ch_id) {
  return (
    enum_type_generateur_ch_id >= 106 ||
    (enum_type_generateur_ch_id >= 55 && enum_type_generateur_ch_id <= 97) ||
    [48, 49, 50, 51, 52].includes(enum_type_generateur_ch_id) ||
    (enum_type_generateur_ch_id >= 4 && enum_type_generateur_ch_id <= 19)
  );
}
/**
 * 18.3 Cas des bâtiments à inertie lourde, constitués de parois anciennes
 *
 * Afin d’être considéré comme un bâtiment à inertie lourde, constitués de parois anciennes, le bâtiment doit :
 * * Etre constitué de murs en matériaux anciens : terre, pierre, brique ancienne, colombage, … ;
 * * Avoir une inertie lourde.
 *
 * En présence de plusieurs types de parois, le bâtiment sera considéré comme constitué de parois anciennes si la surface
 * de parois anciennes est majoritaire.
 * @param dpe {FullDpe}
 */
function isParoisAncienneInertieLourde(dpe) {
  const murs = dpe.logement.enveloppe.mur_collection.mur.filter(
    (mur) => mur.donnee_intermediaire.b > 0
  );
  const nbTotalMurs = murs.length;
  const nbMursAnciens = murs.filter((mur) =>
    ENUM_MATERIAUX_STRUCTURE_MUR_ANCIEN_IDS.includes(
      mur.donnee_entree.enum_materiaux_structure_mur_id
    )
  ).length;
  const isInertieLourde = ENUM_CLASSES_INERTIE_LOURDES_IDS.includes(
    dpe.logement.enveloppe.inertie.enum_classe_inertie_id
  );
  return isInertieLourde && nbMursAnciens / nbTotalMurs >= 0.5;
}