@open3cl/engine
Version: 
Open Source 3CL-DPE engine
301 lines (266 loc) • 9.64 kB
JavaScript
import { requestInput, Tbase, tv, tvColumnIDs } from './utils.js';
import { calc_emetteur_ch } from './9_emetteur_ch.js';
import {
  calc_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';
/**
 * @param dpe {FullDpe}
 */
export default function calc_chauffage(
  dpe,
  ch,
  ca_id,
  zc_id,
  inertie_id,
  map_id,
  bch,
  bch_dep,
  GV,
  Sh,
  hsp,
  ac,
  ilpa,
  besoin_ch_mois
) {
  const de = ch.donnee_entree;
  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;
  const em_ch = ch.emetteur_chauffage_collection.emetteur_chauffage;
  em_ch.forEach((em_ch) => {
    calc_emetteur_ch(em_ch, de, map_id, inertie_id);
  });
  if (de.surface_chauffee !== Sh) {
    bch *= de.surface_chauffee / Sh;
  }
  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.cle_repartition_ch = de.cle_repartition_ch || 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), 0);
  du.Pnominal = Pnominal;
  const nbCascadeAndCombustion = gen_ch.filter(
    (value) =>
      value.donnee_utilisateur.isCombustionGenerator &&
      Number.parseInt(de.enum_cfg_installation_ch_id) === 1
  ).length;
  // 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)) {
      acc++;
    }
    return acc;
  }, 0);
  gen_ch.forEach((gen, _pos) => {
    // Nombre de générateurs en cascade pour un même émetteur si l'installation est une installation simple
    const nbEmetteur = em_ch.filter(
      (em) =>
        em.donnee_entree.enum_lien_generateur_emetteur_id ===
        gen.donnee_entree.enum_lien_generateur_emetteur_id
    ).length;
    const nbCascadeForSameEmetteur =
      Number.parseInt(de.enum_cfg_installation_ch_id) === 1 && nbEmetteur === 1
        ? gen_ch.filter(
            (gen_ch) =>
              gen_ch.donnee_entree.enum_lien_generateur_emetteur_id ===
              gen.donnee_entree.enum_lien_generateur_emetteur_id
          ).length
        : 0;
    const prorataGenerateur = getProrataGenerateur(
      gen,
      nbCascadeAndCombustion,
      nbCascadeForSameEmetteur,
      Pnominal,
      zc
    );
    (gen.donnee_utilisateur = gen.donnee_utilisateur || {}).nbGenerateurCascade = gen_ch.length;
    calc_generateur_ch(
      dpe,
      gen,
      _pos,
      em_ch,
      cfg_id,
      bch * prorataGenerateur,
      bch_dep * prorataGenerateur,
      GV,
      Sh,
      hsp,
      ca_id,
      zc_id,
      ilpa,
      tbase,
      besoin_ch_mois,
      ch.donnee_entree.surface_chauffee,
      gen_ch
    );
    // 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
    ) {
      gen.donnee_intermediaire.conso_auxiliaire_distribution_ch /= nbGenWithAuxConsoDistribution;
    }
  });
  di.conso_ch = gen_ch.reduce((acc, gen_ch) => acc + gen_ch.donnee_intermediaire.conso_ch, 0);
  di.conso_ch_depensier = gen_ch.reduce(
    (acc, gen_ch) => acc + gen_ch.donnee_intermediaire.conso_ch_depensier,
    0
  );
  ch.donnee_intermediaire = di;
  ch.donnee_utilisateur = du;
}
/**
 * 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}
 */
function getProrataGenerateur(genCh, nbCascadeAndCombustion, nbGenerateurCascade, Pnominal, zc) {
  // IDs des pompes à chaleur hybrides
  if (
    genCh.donnee_entree.enum_type_generateur_ch_id >= 145 &&
    genCh.donnee_entree.enum_type_generateur_ch_id <= 170
  ) {
    const zone = zc.slice(0, 2);
    const hybrideProrata = {
      h1: {
        pac: 0.8,
        chaudiere: 0.2
      },
      h2: {
        pac: 0.83,
        chaudiere: 0.17
      },
      h3: {
        pac: 0.88,
        chaudiere: 0.12
      }
    };
    // Partie PAC du générateur
    if (genCh.donnee_intermediaire.scop || genCh.donnee_intermediaire.cop) {
      return hybrideProrata[zone]['pac'];
    } else {
      return hybrideProrata[zone]['chaudiere'];
    }
  }
  return nbCascadeAndCombustion > 1
    ? genCh.donnee_intermediaire.pn / Pnominal
    : 1 / (nbGenerateurCascade || 1);
}
/**
 * Retourne le facteur de couverture solaire pour les maisons avec chauffage solaire
 * @param de {Donnee_entree}
 * @param zc_id {int}
 * @returns {number|*|null}
 */
function tv_ch_facteur_couverture_solaire(de, zc_id) {
  /**
   * 18.4 Facteur de couverture solaire
   * Les facteurs de couverture solaire peuvent être saisi directement quand ils sont connus et peuvent être justifiés.
   */
  if (de.fch_saisi) {
    return de.fch_saisi;
  }
  const matcher = {
    enum_zone_climatique_id: zc_id
  };
  const row = tv('facteur_couverture_solaire', matcher);
  if (row) {
    return Number(row.facteur_couverture_solaire);
  } else {
    console.error('!! pas de valeur forfaitaire trouvée pour facteur_couverture_solaire !!');
    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
  );
  installChauffageWithCombustion.forEach((installCh) => {
    (installCh.donnee_utilisateur.genCombustion || []).forEach((gen) => {
      gen.donnee_utilisateur.cdimref = Pn / (GV * (19 - tbase));
      gen.donnee_utilisateur.cdimrefDep = Pn / (GV * (21 - tbase));
    });
  });
}