Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
6,988 changes: 3,860 additions & 3,128 deletions package-lock.json
100755 → 100644

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@open3cl/engine",
"version": "0.1.0",
"version": "1.0.16",
"description": "Open Source 3CL-DPE engine",
"main": "index.js",
"directories": {
Expand Down Expand Up @@ -55,7 +55,7 @@
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^12.0.2",
"@types/node": "^20.12.4",
"@vitest/coverage-v8": "^3.0.6",
"@vitest/coverage-v8": "^3.2.4",
"ansi-colors": "^4.1.3",
"cli-progress": "^3.12.0",
"deep-object-diff": "^1.1.9",
Expand All @@ -74,7 +74,7 @@
"prettier": "^3.2.5",
"pretty-quick": "^4.0.0",
"semantic-release": "^25.0.2",
"vitest": "3.0.6",
"vitest": "^3.2.4",
"xlsx": "0.18.5"
},
"author": "Open3Cl",
Expand Down
14 changes: 12 additions & 2 deletions src/11_ecs.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,20 @@ export default function calc_ecs(
di.besoin_ecs = becs * di.ratio_besoin_ecs;
di.besoin_ecs_depensier = becs_dep * di.ratio_besoin_ecs;

const pvc = ecs.generateur_ecs_collection.generateur_ecs[0].donnee_entree.position_volume_chauffe;
let pvc = 0; // Default value if generator info is not available
if (
ecs.generateur_ecs_collection &&
ecs.generateur_ecs_collection.generateur_ecs &&
ecs.generateur_ecs_collection.generateur_ecs.length > 0 &&
ecs.generateur_ecs_collection.generateur_ecs[0].donnee_entree
) {
pvc = ecs.generateur_ecs_collection.generateur_ecs[0].donnee_entree.position_volume_chauffe;
}
tv_rendement_distribution_ecs(di, de, du, pvc);

const gen_ecs_list = ecs.generateur_ecs_collection.generateur_ecs;
const gen_ecs_list = Array.isArray(ecs.generateur_ecs_collection?.generateur_ecs)
? ecs.generateur_ecs_collection.generateur_ecs
: [];
gen_ecs_list.forEach((gen_ecs) => calc_gen_ecs(dpe, gen_ecs, di, de, GV, ca_id, zc_id, th));

di.conso_ecs = gen_ecs_list.reduce(
Expand Down
2 changes: 1 addition & 1 deletion src/2021_04_13_confort_ete.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default function calc_confort_ete(inertie_id, bv, ph) {
}, []);
const aspect_traversant = orientations.length > 1 ? 1 : 0;

const isolation_toiture = ph.reduce((acc, ph) => {
const isolation_toiture = (Array.isArray(ph) ? ph : []).reduce((acc, ph) => {
const de = ph.donnee_entree;
const du = ph.donnee_utilisateur;
const type_adjacence = requestInput(de, du, 'type_adjacence');
Expand Down
33 changes: 22 additions & 11 deletions src/2021_04_13_qualite_isolation.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,31 @@ export default function calc_qualite_isolation(enveloppe, dp) {
/**
* enum_type_adjacence_id = 22 - Local non déperditif (local à usage d'habitation chauffé)
*/
const mur_list = (enveloppe.mur_collection.mur || []).filter(
const mur_list = (
Array.isArray(enveloppe.mur_collection?.mur) ? enveloppe.mur_collection.mur : []
).filter(
(mur) => mur.donnee_entree.enum_type_adjacence_id !== '22' && mur.donnee_intermediaire.b > 0
);

const planchersHauts = enveloppe.plancher_haut_collection.plancher_haut || [];
const planchersBas = (enveloppe.plancher_bas_collection.plancher_bas || []).filter(
(mur) => mur.donnee_entree.enum_type_adjacence_id !== '22'
);
const baiesVitrees = (enveloppe.baie_vitree_collection.baie_vitree || []).filter(
(porte) => porte.donnee_intermediaire.b > 0
);
const portes = (enveloppe.porte_collection.porte || []).filter(
(porte) => porte.donnee_intermediaire.b > 0
);
const planchersHauts = Array.isArray(enveloppe.plancher_haut_collection?.plancher_haut)
? enveloppe.plancher_haut_collection.plancher_haut
: [];

const planchersBas = (
Array.isArray(enveloppe.plancher_bas_collection?.plancher_bas)
? enveloppe.plancher_bas_collection.plancher_bas
: []
).filter((mur) => mur.donnee_entree.enum_type_adjacence_id !== '22');

const baiesVitrees = (
Array.isArray(enveloppe.baie_vitree_collection?.baie_vitree)
? enveloppe.baie_vitree_collection.baie_vitree
: []
).filter((porte) => porte.donnee_intermediaire.b > 0);

const portes = (
Array.isArray(enveloppe.porte_collection?.porte) ? enveloppe.porte_collection.porte : []
).filter((porte) => porte.donnee_intermediaire.b > 0);

let phCombleAmenagee = [];
let phCombleToitTerrasse = [];
Expand Down
9 changes: 7 additions & 2 deletions src/3.4_pont_thermique.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ function defaultValue(type_liaison, pt_di, de) {
function tv_k(pt_di, di, de, du, pc_id, logement) {
const enveloppe = logement.enveloppe;

const mur_list = enveloppe.mur_collection.mur || [];
const mur_list =
enveloppe.mur_collection && Array.isArray(enveloppe.mur_collection.mur)
? enveloppe.mur_collection.mur
: [];
const pb_list = enveloppe.plancher_bas_collection.plancher_bas || [];
const ph_list = enveloppe.plancher_haut_collection.plancher_haut || [];
/** @type {BaieVitreeItem[]} **/
Expand Down Expand Up @@ -189,7 +192,9 @@ function tv_k(pt_di, di, de, du, pc_id, logement) {
switch (type_liaison) {
case 'plancher bas / mur':
case 'plancher haut lourd / mur': {
const plancher_list = ph_list.concat(pb_list);
const plancher_list = (Array.isArray(ph_list) ? ph_list : []).concat(
Array.isArray(pb_list) ? pb_list : []
);
const plancher = plancher_list.find(
(plancher) =>
compareReferences(plancher.donnee_entree.reference, de.reference_1) ||
Expand Down
31 changes: 23 additions & 8 deletions src/3_deperdition.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,35 @@ export function Upt(pt) {
return de.l * di.k * (de.pourcentage_valeur_pont_thermique || 1);
}

export default function calc_deperdition(cg, zc, th, effetJoule, dpe, Sh) {
export function calc_deperdition(cg, zc, th, effetJoule, dpe, Sh) {
const pc = cg.enum_periode_construction_id;
const logement = dpe.logement;
const enveloppe = logement.enveloppe;

const mur_list = enveloppe.mur_collection.mur || [];
// Ensure all lists are definitely arrays
const mur_list = Array.isArray(enveloppe?.mur_collection?.mur)
? enveloppe.mur_collection.mur
: [];
const declaredMurs = structuredClone(mur_list);
const pb_list = enveloppe.plancher_bas_collection.plancher_bas || [];
const ph_list = enveloppe.plancher_haut_collection.plancher_haut || [];
const porte_list = enveloppe.porte_collection.porte || [];
const bv_list = enveloppe.baie_vitree_collection.baie_vitree || [];
const pt_list = enveloppe.pont_thermique_collection.pont_thermique || [];
const pb_list = Array.isArray(enveloppe?.plancher_bas_collection?.plancher_bas)
? enveloppe.plancher_bas_collection.plancher_bas
: [];
const ph_list = Array.isArray(enveloppe?.plancher_haut_collection?.plancher_haut)
? enveloppe.plancher_haut_collection.plancher_haut
: [];
const porte_list = Array.isArray(enveloppe?.porte_collection?.porte)
? enveloppe.porte_collection.porte
: [];
const bv_list = Array.isArray(enveloppe?.baie_vitree_collection?.baie_vitree)
? enveloppe.baie_vitree_collection.baie_vitree
: [];
const pt_list = Array.isArray(enveloppe?.pont_thermique_collection?.pont_thermique)
? enveloppe.pont_thermique_collection.pont_thermique
: [];
const declaredPontsThermiques = structuredClone(pt_list);
const vt_list = logement.ventilation_collection.ventilation || [];
const vt_list = Array.isArray(logement?.ventilation_collection?.ventilation)
? logement.ventilation_collection.ventilation
: [];

mur_list.forEach((mur) => calc_mur(mur, zc, pc, effetJoule));
pb_list.forEach((pb) => calc_pb(pb, zc, pc, effetJoule, pb_list));
Expand Down
16 changes: 15 additions & 1 deletion src/7_inertie.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ export class Inertie {
this.calculateInertiePhLourd
),
inertie_paroi_verticale_lourd: this.#calculateInertieForCollection(
enveloppe.mur_collection.mur || [],
enveloppe && enveloppe.mur_collection && Array.isArray(enveloppe.mur_collection.mur)
? enveloppe.mur_collection.mur
: [],
this.calculateInertieMurLourd
)
};
Expand All @@ -168,11 +170,23 @@ export class Inertie {
* @returns {number}
*/
#calculateInertieForCollection(collection, method) {
// Check if collection exists and is an array
if (!collection || !Array.isArray(collection) || collection.length === 0) {
return 0; // Return 0 for empty or non-array collections
}

const s_lourd = collection.reduce((acc, item) => {
const de = item.donnee_entree;
return acc + de.surface_paroi_opaque * method(de);
}, 0);

const s_total = collection.reduce((acc, pb) => acc + pb.donnee_entree.surface_paroi_opaque, 0);

// Prevent division by zero
if (s_total === 0) {
return 0;
}

return s_lourd / s_total >= 0.5 ? 1 : 0;
}
}
5 changes: 5 additions & 0 deletions src/9_besoin_ch.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ export default function calc_besoin_ch(
let fraction_apport_gratuit_ch = 0;
let fraction_apport_gratuit_depensier_ch = 0;

// Ensure instal_ecs is always an array
instal_ecs = Array.isArray(instal_ecs) ? instal_ecs : [];
// Ensure instal_ch is always an array
instal_ch = Array.isArray(instal_ch) ? instal_ch : [];

/**
* 11.4 Plusieurs systèmes d’ECS (limité à 2 systèmes différents par logement)
* Les besoins en ECS pour chaque générateur sont / 2
Expand Down
4 changes: 2 additions & 2 deletions src/apport_et_besoin.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export default function calc_apport_et_besoin(
const enveloppe = logement.enveloppe;
const inertie = enums.classe_inertie[enveloppe.inertie.enum_classe_inertie_id];

const bv = enveloppe.baie_vitree_collection.baie_vitree;
const ets = enveloppe.ets_collection.ets;
const bv = enveloppe.baie_vitree_collection?.baie_vitree || [];
const ets = enveloppe.ets_collection?.ets || [];

const nadeq = nadeqService.calculateNadeq(logement);

Expand Down
2 changes: 2 additions & 0 deletions src/conso.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ export default function calc_conso(
return acc.concat(generateur_chauffage);
}, []);

ecs = Array.isArray(ecs) ? ecs : [];

const gen_ecs = ecs.reduce((acc, ecs) => {
const generateur_ecs = ecs.generateur_ecs_collection.generateur_ecs;
if (prorataECS === 1) {
Expand Down
50 changes: 36 additions & 14 deletions src/engine.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import enums from './enums.js';
import calc_deperdition from './3_deperdition.js';
import { calc_deperdition } from './3_deperdition.js';
import calc_apport_et_besoin from './apport_et_besoin.js';
import calc_clim from './10_clim.js';
import calc_ecs from './11_ecs.js';
Expand Down Expand Up @@ -63,10 +63,10 @@ export function calcul_3cl(dpe) {

if (logement.enveloppe === undefined) {
console.warn('vide: logement.enveloppe');
return null;
//return null;
} else if (!logement.enveloppe.mur_collection) {
console.warn('vide: logement.enveloppe.mur_collection');
return null;
//return null;
} else if (
!logement.enveloppe.plancher_haut_collection ||
!logement.enveloppe.plancher_haut_collection.plancher_haut.length
Expand All @@ -83,7 +83,7 @@ export function calcul_3cl(dpe) {
};
} else {
console.error('plancher_bas_collection should not be empty');
return null;
//return null;
}
} else if (
!logement.enveloppe.plancher_bas_collection ||
Expand All @@ -101,7 +101,7 @@ export function calcul_3cl(dpe) {
};
} else {
console.error('plancher_bas_collection should not be empty');
return null;
//return null;
}
}

Expand Down Expand Up @@ -165,7 +165,11 @@ export function calcul_3cl(dpe) {
const zc_id = logement.meteo.enum_zone_climatique_id;
const ca_id = logement.meteo.enum_classe_altitude_id;

const instal_ch = logement.installation_chauffage_collection.installation_chauffage;
const instal_ch = Array.isArray(
logement.installation_chauffage_collection?.installation_chauffage
)
? logement.installation_chauffage_collection.installation_chauffage
: [];
const bv_list = env.baie_vitree_collection.baie_vitree;

bv_list.forEach((baieVitree) => {
Expand Down Expand Up @@ -213,10 +217,24 @@ export function calcul_3cl(dpe) {
'valeur'
);

logement.ventilation_collection.ventilation.forEach((ventilation) => {
ventilation.donnee_entree.ficheTechniqueFacadesExposees = ficheTechniqueFacadesExposees;
ventilation.donnee_entree.ficheTechniqueVentilationPost2012 = ficheTechniqueVentilationPost2012;
});
// Ensure ventilation collection is properly initialized
if (!logement.ventilation_collection) {
logement.ventilation_collection = { ventilation: [] };
}

// Check if ventilation is an array before using forEach
if (logement.ventilation_collection.ventilation) {
if (!Array.isArray(logement.ventilation_collection.ventilation)) {
// If it's an object but not an array, convert it to an array with this object as its only element
logement.ventilation_collection.ventilation = [logement.ventilation_collection.ventilation];
}

logement.ventilation_collection.ventilation.forEach((ventilation) => {
ventilation.donnee_entree.ficheTechniqueFacadesExposees = ficheTechniqueFacadesExposees;
ventilation.donnee_entree.ficheTechniqueVentilationPost2012 =
ficheTechniqueVentilationPost2012;
});
}

const deperdition = calc_deperdition(
cg,
Expand Down Expand Up @@ -287,18 +305,21 @@ export function calcul_3cl(dpe) {
* 11.4 Plusieurs systèmes d’ECS (limité à 2 systèmes différents par logement)
* Les besoins en ECS pour chaque générateur sont / 2
*/
if (ecs.length > 1) {
// Make sure ecs is an array before using length
const ecsArray = Array.isArray(ecs) ? ecs : ecs ? [ecs] : [];

if (ecsArray.length > 1) {
// Immeuble avec différents systèmes individuels
isImmeubleSystemEcsIndividuels =
th === 'immeuble' && ecs.every((e) => e.donnee_entree.enum_type_installation_id === '1');
th === 'immeuble' && ecsArray.every((e) => e.donnee_entree.enum_type_installation_id === '1');

if (!isImmeubleSystemEcsIndividuels) {
becs /= 2;
becs_dep /= 2;
}
}

ecs.forEach((ecs) => {
ecsArray.forEach((ecs) => {
if (bug_for_bug_compat) {
/**
* Réalignement si besoin de la variable position_volume_chauffe
Expand Down Expand Up @@ -409,6 +430,7 @@ export function calcul_3cl(dpe) {

const ac = cg.annee_construction;
// needed for apport_et_besoin

instal_ch.forEach((ch) => {
ch.donnee_entree.ficheTechniqueComptage = ficheTechniqueComptage;
calc_chauffage(
Expand All @@ -428,7 +450,7 @@ export function calcul_3cl(dpe) {
);
});

const ets = env.ets_collection.ets;
const ets = env.ets_collection?.ets || [];

const besoin_ch = calc_besoin_ch(
ilpa,
Expand Down
Loading