diff --git a/src/2021_04_13_qualite_isolation.js b/src/2021_04_13_qualite_isolation.js index 697542b..cb7a7da 100644 --- a/src/2021_04_13_qualite_isolation.js +++ b/src/2021_04_13_qualite_isolation.js @@ -49,7 +49,7 @@ export default function calc_qualite_isolation(enveloppe, dp) { } else { if ( plancherHaut.donnee_entree.enum_type_plancher_haut_id === '12' || - plancherHaut.donnee_entree.description.toLowerCase().indexOf('combles aménagés') !== -1 + plancherHaut.donnee_entree.description?.toLowerCase().indexOf('combles aménagés') !== -1 ) { phCombleAmenagee.push(plancherHaut); } else { diff --git a/src/3.2.2_plancher_bas.js b/src/3.2.2_plancher_bas.js index e56c613..de7345b 100644 --- a/src/3.2.2_plancher_bas.js +++ b/src/3.2.2_plancher_bas.js @@ -1,6 +1,6 @@ import enums from './enums.js'; import b from './3.1_b.js'; -import { tv, requestInput, getKeyByValue, bug_for_bug_compat } from './utils.js'; +import { tv, requestInput, getKeyByValue, bug_for_bug_compat, getRange } from './utils.js'; const scriptName = new URL(import.meta.url).pathname.split('/').pop(); @@ -53,36 +53,6 @@ function tv_upb(di, de, du, pc_id, zc, effetJoule) { } } -function ue_ranges(inputNumber, ranges) { - const result = []; - - if (inputNumber < ranges[0]) { - result.push(ranges[0]); - result.push(ranges[1]); - } - if (inputNumber > ranges[ranges.length - 1]) { - result.push(ranges[ranges.length - 2]); - result.push(ranges[ranges.length - 1]); - } - if (ranges.includes(inputNumber)) { - result.push(inputNumber); - result.push(inputNumber); - } else { - ranges.find((range, index) => { - if (inputNumber < range) { - if (index > 0) { - result.push(ranges[index - 1]); - } else { - result.push(ranges[index]); - } - result.push(ranges[index]); - return true; - } - }); - } - return result; -} - const values_2s_p = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20]; function tv_ue(di, de, du, pc_id, pb_list) { @@ -92,14 +62,14 @@ function tv_ue(di, de, du, pc_id, pb_list) { if (type_adjacence === 'terre-plein') { if (Number(pc_id) < 7) { type_adjacence_plancher = 'terre plein bâtiment construit avant 2001'; - [upb1, upb2] = ue_ranges(di.upb, [0.46, 0.59, 0.85, 1.5, 3.4]); + [upb1, upb2] = getRange(di.upb, [0.46, 0.59, 0.85, 1.5, 3.4]); } else { type_adjacence_plancher = 'terre plein bâtiment construit à partir de 2001'; - [upb1, upb2] = ue_ranges(di.upb, [0.31, 0.37, 0.46, 0.6, 0.85, 1.5, 3.4]); + [upb1, upb2] = getRange(di.upb, [0.31, 0.37, 0.46, 0.6, 0.85, 1.5, 3.4]); } } else { type_adjacence_plancher = 'plancher sur vide sanitaire ou sous-sol non chauffé'; - [upb1, upb2] = ue_ranges(di.upb, [0.31, 0.34, 0.37, 0.41, 0.45, 0.83, 1.43, 3.33]); + [upb1, upb2] = getRange(di.upb, [0.31, 0.34, 0.37, 0.41, 0.45, 0.83, 1.43, 3.33]); } /** diff --git a/src/3.3_baie_vitree.js b/src/3.3_baie_vitree.js index ce2a139..1c4fe81 100644 --- a/src/3.3_baie_vitree.js +++ b/src/3.3_baie_vitree.js @@ -1,5 +1,6 @@ import b from './3.1_b.js'; -import { tv, requestInput, requestInputID, bug_for_bug_compat } from './utils.js'; +import { tv, requestInput, requestInputID, bug_for_bug_compat, getRange } from './utils.js'; +import tvs from './tv.js'; function tv_ug(di, de, du) { const matcher = { @@ -22,24 +23,73 @@ function tv_ug(di, de, du) { } } -function tv_uw(di, de, du) { - const matcher = { - enum_type_baie_id: requestInputID(de, du, 'type_baie') - }; +function tv_uw(di, de) { + const enum_type_baie_id = de.enum_type_baie_id; + const matcher = { enum_type_baie_id }; + let uw; + + /** + * Pas de notion de ug pour les parois polycarbonate ou verre + * enum_type_baie_id + * 1 - paroi en brique de verre pleine + * 2 - paroi en brique de verre creuse + * 3 - paroi en polycarbonnate + */ + if (matcher.enum_type_baie_id && ['1', '2', '3'].includes(enum_type_baie_id)) { + const row = tv('uw', matcher); + if (row) { + uw = Number(row.uw); + de.tv_uw_id = Number(row.tv_uw_id); + } + } else { + const enum_type_materiaux_menuiserie_id = de.enum_type_materiaux_menuiserie_id; + matcher.enum_type_materiaux_menuiserie_id = enum_type_materiaux_menuiserie_id; + + // Récupération de toutes les valeurs de Ug présentes dans les tables Uw pour le type de baie et matériaux de la baie vitrée + const ugValues = tvs.uw + .filter((row) => { + return ( + row.enum_type_baie_id.split('|').includes(enum_type_baie_id) && + row.enum_type_materiaux_menuiserie_id + .split('|') + .includes(enum_type_materiaux_menuiserie_id) + ); + }) + .map((row) => parseFloat(row.ug)); + + /** + * 3.3.2 Coefficients Uw des fenêtres / portes-fenêtres + * Les Uw associés à des Ug non présents dans les tableaux peuvent être obtenus par interpolation ou + * extrapolation avec les deux Ug tabulés les plus proches. + */ + let ug1, ug2; + [ug1, ug2] = getRange(di.ug, ugValues); + + const matcher_1 = { ...matcher, ...{ ug: `^${ug1}$` } }; + const row_1 = tv('uw', matcher_1); + const delta_ug = ug2 - ug1; + + if (delta_ug === 0) { + if (row_1) { + uw = Number(row_1.uw); + } + } else { + const matcher_2 = { ...matcher, ...{ ug: `^${ug2}$` } }; + const row_2 = tv('uw', matcher_2); - if ( - matcher.enum_type_baie_id && - !['1', '2', '3'].includes(matcher.enum_type_baie_id.toString()) - ) { - matcher.enum_type_materiaux_menuiserie_id = requestInputID(de, du, 'type_materiaux_menuiserie'); - matcher.ug = `^${di.ug}$`; + if (row_1 && row_2) { + const delta_uw = Number(row_2.uw) - Number(row_1.uw); + uw = Number(row_1.uw) + (delta_uw * (di.ug - ug1)) / delta_ug; + } + } } - const row = tv('uw', matcher); - if (row) { - di.uw = Number(row.uw); - de.tv_uw_id = Number(row.tv_uw_id); + + if (uw) { + di.uw = uw; } else { - console.error('!! pas de valeur forfaitaire trouvée pour uw !!'); + console.error(` + Pas de valeur forfaitaire uw trouvée pour la baie vitrée ${de.description}. + `); } } @@ -158,7 +208,7 @@ export default function calc_bv(bv, zc) { tv_ug(di, de, du); if (de.uw_saisi) di.uw = de.uw_saisi; - else tv_uw(di, de, du); + else tv_uw(di, de); /** * S'il existe une double-fenêtre, calcul des facteurs sw et uw équivalents @@ -196,7 +246,7 @@ export default function calc_bv(bv, zc) { if (deDoubleFenetre.uw_saisi) { diDoubleFenetre.uw = deDoubleFenetre.uw_saisi; } else { - tv_uw(diDoubleFenetre, deDoubleFenetre, du); + tv_uw(diDoubleFenetre, deDoubleFenetre); } const uw = 1 / (1 / di.uw + 1 / diDoubleFenetre.uw + 0.07); diff --git a/src/engine.js b/src/engine.js index 2917fcd..ddc160b 100644 --- a/src/engine.js +++ b/src/engine.js @@ -285,29 +285,31 @@ export function calcul_3cl(dpe) { * dans tous les DPEs (parfois 0 = 'Oui', d'autres 0 = 'Non') */ ecs.generateur_ecs_collection.generateur_ecs.forEach((generateur) => { - const ficheProductionVolumeHabitable = getFicheTechnique( - dpe, - '8', - 'hors volume habitable', - [generateur.donnee_entree.description] - ); - - if (ficheProductionVolumeHabitable) { - const pvcFicheTechnique = containsAnySubstring(ficheProductionVolumeHabitable.valeur, [ + if (generateur.donnee_entree.description) { + const ficheProductionVolumeHabitable = getFicheTechnique( + dpe, + '8', 'hors volume habitable', - 'oui' - ]) - ? 0 - : 1; - - if (generateur.donnee_entree.position_volume_chauffe !== pvcFicheTechnique) { - console.error( - `La valeur de la variable position_volume_chauffe pour le générateur ECS ${generateur.donnee_entree.description} + [generateur.donnee_entree.description] + ); + + if (ficheProductionVolumeHabitable) { + const pvcFicheTechnique = containsAnySubstring(ficheProductionVolumeHabitable.valeur, [ + 'hors volume habitable', + 'oui' + ]) + ? 0 + : 1; + + if (generateur.donnee_entree.position_volume_chauffe !== pvcFicheTechnique) { + console.error( + `La valeur de la variable position_volume_chauffe pour le générateur ECS ${generateur.donnee_entree.description} ne correspond pas à celle présente dans la fiche technique "${ficheProductionVolumeHabitable.description}". La valeur de la fiche technique est prise en compte.` - ); + ); - generateur.donnee_entree.position_volume_chauffe = pvcFicheTechnique; + generateur.donnee_entree.position_volume_chauffe = pvcFicheTechnique; + } } } diff --git a/src/ficheTechnique.js b/src/ficheTechnique.js index f64513d..a454c64 100644 --- a/src/ficheTechnique.js +++ b/src/ficheTechnique.js @@ -22,6 +22,8 @@ export default function getFicheTechnique( fichesTechniques = [fichesTechniques]; } + classifications = classifications.filter((classification) => classification); + fichesTechniques = fichesTechniques .filter((ficheTechnique) => ficheTechnique) .reduce((acc, ficheTechnique) => { diff --git a/src/utils.js b/src/utils.js index df87966..10dd133 100644 --- a/src/utils.js +++ b/src/utils.js @@ -435,7 +435,9 @@ export function isEffetJoule(instal_ch) { * @returns {boolean} */ export function containsAnySubstring(mainString, substrings) { - return substrings.some((substring) => mainString.toLowerCase().includes(substring.toLowerCase())); + return substrings.some((substring) => + mainString.toString().toLowerCase().includes(substring.toLowerCase()) + ); } /** @@ -455,3 +457,44 @@ export function convertExpression(expression) { ); return expression; } + +/** + * Retourne les valeurs qui encadrent inputNumber dans ranges + * Si inputNumber est présent dans ranges, inputNumber est retourné comme borne 1 et borne 2 + * + * @param inputNumber {float} + * @param ranges {number[]} + * @returns {*[]} + */ +export function getRange(inputNumber, ranges) { + const result = []; + + ranges.sort(); + + if (inputNumber < ranges[0]) { + result.push(ranges[0]); + result.push(ranges[1]); + return result; + } + if (inputNumber > ranges[ranges.length - 1]) { + result.push(ranges[ranges.length - 2]); + result.push(ranges[ranges.length - 1]); + } + if (ranges.includes(inputNumber)) { + result.push(inputNumber); + result.push(inputNumber); + } else { + ranges.find((range, index) => { + if (inputNumber < range) { + if (index > 0) { + result.push(ranges[index - 1]); + } else { + result.push(ranges[index]); + } + result.push(ranges[index]); + return true; + } + }); + } + return result; +} diff --git a/src/utils.spec.js b/src/utils.spec.js index 58b1d74..585c644 100644 --- a/src/utils.spec.js +++ b/src/utils.spec.js @@ -1,4 +1,4 @@ -import { convertExpression, getThicknessFromDescription } from './utils.js'; +import { convertExpression, getRange, getThicknessFromDescription } from './utils.js'; describe('Utils unit tests', () => { it.each([ @@ -24,4 +24,13 @@ describe('Utils unit tests', () => { ])('should transform expression %s to %s', (expression, expected) => { expect(convertExpression(expression)).toBe(expected); }); + + it.each([ + [[1, 1.2, 3.4, 5.6], 0.5, [1, 1.2]], + [[1, 1.2, 3.4, 5.6], 1, [1, 1]], + [[1, 1.2, 3.4, 5.6], 1.3, [1.2, 3.4]], + [[1, 1.2, 3.4, 5.6], 6.5, [3.4, 5.6]] + ])('should for values %s and inputNumber %s return range %s', (ranges, inputNumber, expected) => { + expect(getRange(inputNumber, ranges)).toStrictEqual(expected); + }); });