diff --git a/spec/pab/pab.spec.ts b/spec/pab/pab.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ff7a5a54589a2d441132e4519141507d162188b --- /dev/null +++ b/spec/pab/pab.spec.ts @@ -0,0 +1,95 @@ +/** + * IMPORTANT ! + * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine") + * Pour exécuter ce code dans le débugger. + * Faire de même avec le fichier test_func.ts + */ +// import { describe, expect, it, xdescribe, xit } from "../mock_jasmine"; + +import { Pab, PabParams } from "../../src/pab/pab"; +import { PabCloisons } from "../../src/pab/pab_cloisons"; +import { Cloisons, CloisonsParams } from "../../src/structure/cloisons"; +import { ParallelStructure, ParallelStructureParams } from "../../src/structure/parallel_structure"; +import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params"; +import { StructureKivi, StructureKiviParams } from "../../src/structure/structure_kivi"; +import { StructureWeirSubmergedLarinier } from "../../src/structure/structure_weir_submerged_larinier"; + +const dbg: boolean = false; + +/** + * Exemple formation Cassiopée 2018-09 + */ + +// Modèle de cloison +const modelCloisons = new Cloisons( + new CloisonsParams( + 0.773, // Débit total (m3/s) + 78.27, // Cote de l'eau amont (m) + 3.1, // Longueur des bassins (m) + 2.5, // Largeur des bassins (m) + 1.5, // Profondeur moyenne (m) + 0.23 // Hauteur de chute (m) + ) +); + +const rectStructPrms = new RectangularStructureParams( + 0.773, // Q + 76.67, // ZDV + 0, // Z1 + 0, // Z2 + 0.35, // L + 0.65 // Cd pour un seuil rectangulaire + // W = Infinity par défaut pour un seuil +); + +// Ajout d'ouvrage dans la cloison +modelCloisons.addChild(new StructureWeirSubmergedLarinier(rectStructPrms)); + +// Création de la cloison aval +const downWall = new ParallelStructure(new ParallelStructureParams(0, 0, 0)); +const kiviPrms = new StructureKiviParams( + 0.773, // Q + 73.95, // ZDV + 0, // Z1 + 0, // Z2 + 0.6, // L + 0.4, // Cd pour un seuil rectangulaire + 0, + 73.435 +); +downWall.addChild(new StructureKivi(kiviPrms)); + +// Création de la passe +const pab: Pab = new Pab( + new PabParams( + modelCloisons.prms.Q.v, + 100, + 74.86 + ), + downWall, + dbg +); + +// Ajout des cloisons + +const pabCloison = new PabCloisons(modelCloisons, 0, dbg); + +for (let i = 0; i < 14; i++) { + pab.addChild(pabCloison); +} + +// Tests + +describe("Class Pab: ", () => { + describe("Exemple Formation 2018-09 p.14", () => { + it("CalcSerie(Z1) should return 78.27", () => { + pab.calculatedParam = pab.prms.Z1; + expect(pab.CalcSerie().vCalc).toBeCloseTo(78.27, 2); + }); + it("Calc(Q) should return 0.773", () => { + pab.prms.Z1.v = modelCloisons.prms.Z1.v; + pab.prms.Q.v = 0; + expect(pab.Calc("Q").vCalc).toBeCloseTo(0.773, 2); + }); + }); +}); diff --git a/spec/pab/pab_chute.spec.ts b/spec/pab/pab_chute.spec.ts index 4fe6f25d757b7b98ccac00f8bbc0a440a2b021e4..2f2f5b5943be7218fe42cfc69fbff14952da8aec 100644 --- a/spec/pab/pab_chute.spec.ts +++ b/spec/pab/pab_chute.spec.ts @@ -25,4 +25,16 @@ describe("Class PabChute: ", () => { pabChuteTest("Z2", 0.5); pabChuteTest("DH", 1.5); + it ("Z1 < Z2 should lead to log error entry", () => { + const prms = new PabChuteParams( + 100, // Cote amont Z1 + 100.5, // Cote aval Z2 + 1.5, // Chute DH + ); + + const nub = new PabChute(prms); + + expect(nub.Calc("DH", 0).log.messages.length).toBeGreaterThan(0); + }); + }); diff --git a/spec/pab/pab_nombre.spec.ts b/spec/pab/pab_nombre.spec.ts index fb5d9619e763d67cad5ce5d2e9099f74e4dba854..9136553725fb39bdb301f17c33c949d9d40a942b 100644 --- a/spec/pab/pab_nombre.spec.ts +++ b/spec/pab/pab_nombre.spec.ts @@ -28,13 +28,40 @@ describe("Class PabNombre: ", () => { it ("DHR should be 0.3", () => { const prms = new PabNombreParams( 7.5, // Chute totale DHT - 9, // Nombre de bassins N + 666, // Nombre de bassins N 0.8, // Chute entre bassins DH ); const nub = new PabNombre(prms); nub.Calc("N", 0); + expect(nub.result.vCalc).toBe(9); expect(nub.result.getExtraResult("DHR")).toBeCloseTo(0.3); }); + + it ("DHR should be 0", () => { + const prms = new PabNombreParams( + 3, // Chute totale DHT + 666, // Nombre de bassins N + 0.2, // Chute entre bassins DH + ); + + const nub = new PabNombre(prms); + + nub.Calc("N", 0); + expect(nub.result.vCalc).toBe(15); + expect(nub.result.getExtraResult("DHR")).toBe(0); + }); + + it ("non-integer number of basins should lead to log error entry", () => { + const prms = new PabNombreParams( + 3, // Chute totale DHT + 4.5, // Nombre de bassins N + 0.2, // Chute entre bassins DH + ); + + const nub = new PabNombre(prms); + + expect(nub.Calc("DH", 0).log.messages.length).toBeGreaterThan(0); + }); }); diff --git a/spec/param/param_modes.spec.ts b/spec/param/param_modes.spec.ts index ab9a2c1a1943f5be6aceb708043a5f1dc0280198..9ed7a9cc66b6ced69e6ae2adedb9c80f0e8c1273 100644 --- a/spec/param/param_modes.spec.ts +++ b/spec/param/param_modes.spec.ts @@ -1,5 +1,8 @@ -import { cSnTrapez, LinkedValue, Nub, ParallelStructure, ParallelStructureParams, - ParamsSectionTrapez, ParamValueMode, SectionParametree, Session } from "../../src/index"; +import { + cSnTrapez, LinkedValue, Nub, ParallelStructure, ParallelStructureParams, + ParamCalculability, ParamsSectionTrapez, ParamValueMode, SectionParametree, + Session +} from "../../src/index"; import { RegimeUniforme } from "../../src/regime_uniforme"; import { cSnCirc, ParamsSectionCirc } from "../../src/section/section_circulaire"; import { Cloisons } from "../../src/structure/cloisons"; @@ -162,23 +165,22 @@ function testModesPermutations(nubToTest: Nub) { // set every parameter to CALC mode for (const p of nubToTest.parameterIterator) { - if (p.symbol === "Pr" || ! p.visible) { - continue; + if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(p.calculability) && p.visible) { + p.setCalculated(); + checkConsistency(nubToTest); } - p.setCalculated(); - checkConsistency(nubToTest); } // set every parameter to MINMAX / LISTE mode let i = 0; for (const p of nubToTest.parameterIterator) { - if (p.symbol === "Pr" || ! p.visible) { + if (p.symbol === "Pr" || !p.visible) { continue; } if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } checkConsistency(nubToTest); i++; @@ -186,18 +188,17 @@ function testModesPermutations(nubToTest: Nub) { // set every parameter to CALC then to SINGLE mode for (const p of nubToTest.parameterIterator) { - if (p.symbol === "Pr" || ! p.visible) { - continue; + if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(p.calculability) && p.visible) { + p.setCalculated(); + checkConsistency(nubToTest); + p.valueMode = ParamValueMode.SINGLE; + checkConsistency(nubToTest); } - p.setCalculated(); - checkConsistency(nubToTest); - p.valueMode = ParamValueMode.SINGLE; - checkConsistency(nubToTest); } // set every parameter to LINK mode then to SINGLE mode for (const p of nubToTest.parameterIterator) { - if (p.symbol === "Pr" || ! p.visible) { + if (p.symbol === "Pr" || !p.visible) { continue; } const lv: LinkedValue[] = Session.getInstance().getLinkableValues(p); @@ -248,7 +249,7 @@ describe("cohérence des modes de paramètres : ", () => { prm1.Q.setValues(0.6, 2.4, 0.09); // link other Nubs Q to nub1.Q - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub1.section, "Q"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -257,7 +258,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); @@ -275,7 +276,7 @@ describe("cohérence des modes de paramètres : ", () => { prm6.Q.defineReference(nub1.section, "Q"); // link other Nubs Q to nub6.Q - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub6.section, "Q"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -284,7 +285,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); @@ -300,7 +301,7 @@ describe("cohérence des modes de paramètres : ", () => { prm1.Q.setCalculated(); // link other Nubs Q to nub1.Q - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub1, "Q"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -309,7 +310,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); @@ -328,7 +329,7 @@ describe("cohérence des modes de paramètres : ", () => { prm6.Q.defineReference(nub1, "Q"); // link other Nubs Q to nub6.Q - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub6.section, "Q"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -337,7 +338,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); @@ -353,7 +354,7 @@ describe("cohérence des modes de paramètres : ", () => { prm5.Q.setCalculated(); // link other Nubs Q to nub5.CvQT - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub5, "CvQT"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -362,7 +363,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); @@ -381,7 +382,7 @@ describe("cohérence des modes de paramètres : ", () => { prm6.Q.defineReference(nub5, "CvQT"); // link other Nubs Q to nub6.Q - for (const n of [ nub2, nub3, nub4 ]) { + for (const n of [nub2, nub3, nub4]) { n.prms.Q.defineReference(nub6.section, "Q"); // set every parameter to MINMAX / LISTE mode let i = 0; @@ -390,7 +391,7 @@ describe("cohérence des modes de paramètres : ", () => { if (i % 2 === 0) { p.setValues(1, 5, 0.5); // sets valueMode to MINMAX } else { - p.setValues([ 1, 2, 3, 4, 5 ]); // sets valueMode to LISTE + p.setValues([1, 2, 3, 4, 5]); // sets valueMode to LISTE } } checkConsistency(n); diff --git a/spec/real.spec.ts b/spec/real.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab26118764a183e0f160c09247e8677c292a472f --- /dev/null +++ b/spec/real.spec.ts @@ -0,0 +1,39 @@ +import { floatDivAndMod, isEqual } from "../src/base"; + +/** + * Tests d'égalité, de divisions entières et de modulo, à la tolérance près + */ + +const divAndModCases = [ + { D: 3, d: 0.2, q: 15, r: 0 }, + { D: 3, d: 0.1, q: 30, r: 0 }, + { D: 3, d: 0.3, q: 10, r: 0 }, + { D: 3, d: 3, q: 1, r: 0 }, + { D: 3, d: 3.00000000001, q: 1, r: 0 } +]; + +for (const c of divAndModCases) { + describe("real numbers division and modulo - ", () => { + it(`(${c.D} / ${c.d}) should be ${c.q}, (${c.D} % ${c.d}) should be ${c.r}`, () => { + const divAndMod = floatDivAndMod(c.D, c.d); + expect(divAndMod.q).toBe(c.q); + expect(divAndMod.r).toBe(c.r); + }); + }); +} + +const eqCases = [ + { a: 0, b: 0, eq: true }, + { a: 0, b: 0.0000000000001, eq: true }, + { a: 0.0000000000001, b: 0, eq: true }, + { a: 0.0000000000001, b: 0.0000000000001, eq: true }, + { a: 0, b: 0.1, eq: false } +]; + +for (const c of eqCases) { + describe("real numbers equality - ", () => { + it(c.a + " should " + (c.eq ? "" : "not ") + " be equal to " + c.b, () => { + expect(isEqual(c.a, c.b)).toBe(c.eq); + }); + }); +} diff --git a/spec/session/serialisation.spec.ts b/spec/session/serialisation.spec.ts index 591d6401273cb891be9c27f94ed319dcfd917a55..6a6e93e90b724cf62df6f097c9bf54b12fb2a75a 100644 --- a/spec/session/serialisation.spec.ts +++ b/spec/session/serialisation.spec.ts @@ -144,7 +144,7 @@ describe("serialising / deserialising session - ", () => { ); const section = new cSnCirc(paramSection); const sp = new SectionParametree(section); - sp.section.prms.Ks.v = 42; + sp.section.prms.Ks.singleValue = 42; const serialised = sp.serialise(); expect(serialised).toContain('{"symbol":"Ks","mode":"SINGLE","value":42}'); diff --git a/spec/structure/cloisons.spec.ts b/spec/structure/cloisons.spec.ts index 9e52d240ce214aa388913fde50ff506922e47f1c..65b3991d7a65d359d7f1af6e8f7ad6042fc1e4f0 100644 --- a/spec/structure/cloisons.spec.ts +++ b/spec/structure/cloisons.spec.ts @@ -6,6 +6,7 @@ */ // import { describe, expect, it, xdescribe, xit } from "../mock_jasmine"; +import { ParamDefinition } from "../../src/index"; import { Cloisons } from "../../src/structure/cloisons"; import { CloisonsParams } from "../../src/structure/cloisons_params"; import { CreateStructure } from "../../src/structure/factory_structure"; @@ -41,6 +42,7 @@ const fente: StructureWeirSubmergedLarinier = new StructureWeirSubmergedLarinier cloisons.addChild(fente); describe("Class Cloisons: ", () => { + describe("Calc(Q) Fente noyée (Larinier 1992)", () => { it("vCalc should return 0.407", () => { expect(cloisons.Calc("Q").vCalc).toBeCloseTo(0.407, 3); @@ -68,7 +70,7 @@ describe("Class Cloisons: ", () => { LoiDebit.WeirSubmergedLarinier, LoiDebit.KIVI ]; - for (let i = 0; i < 3; i++ ) { + for (let i = 0; i < 3; i++) { c2.addChild(CreateStructure(iLoiDebits[i], c2, false)); } const prmsKivi: StructureKiviParams = c2.structures[2].prms as StructureKiviParams; @@ -82,4 +84,96 @@ describe("Class Cloisons: ", () => { expect(prmsKivi.ZRAM.v).toBeCloseTo(101, 3); }); }); + + describe("Calcul avec Calc - ", () => { + const descs = [ + "Q", + "Z1", + "DH" + ]; + for (const desc of descs) { + describe("calcul de " + JSON.stringify(desc), () => { + it("", () => { + expect(cloisons.Calc(desc).vCalc).toBeDefined(); + }); + }); + } + }); + + describe("Calcul avec CalcSerie - ", () => { + const descs = [ + "Q", + "Z1", + "DH", + { uid: fente.uid, symbol: "ZDV" }, + { uid: fente.uid, symbol: "L" }, + { uid: fente.uid, symbol: "Cd" } + ]; + for (const desc of descs) { + describe("calcul de " + JSON.stringify(desc), () => { + it("", () => { + expect(cloisons.CalcSerie(0, desc).vCalc).toBeDefined(); + }); + }); + } + }); + + describe("Calcul avec CalcSerie et calculatedParam - ", () => { + const descs = [ + "Q", + "Z1", + "DH", + { uid: fente.uid, symbol: "ZDV" }, + { uid: fente.uid, symbol: "L" }, + { uid: fente.uid, symbol: "Cd" } + ]; + for (const desc of descs) { + describe("calcul de " + JSON.stringify(desc), () => { + it("", () => { + let p: ParamDefinition; + if (typeof desc === "string") { + p = cloisons.getParameter(desc); + } else { + p = fente.getParameter(desc.symbol); + } + cloisons.calculatedParam = p; + expect(cloisons.CalcSerie().vCalc).toBeDefined(); + }); + }); + } + }); + + describe("Exemple Formation Cassiopée 2018-09", () => { + it("Calc(Z1) Exemple Formation Cassiopée 2018-09", () => { + // Modèle de cloison + const modelCloisons = new Cloisons( + new CloisonsParams( + 0.773, // Débit total (m3/s) + 102, // Cote de l'eau amont (m) + 3.1, // Longueur des bassins (m) + 2.5, // Largeur des bassins (m) + 1.5, // Profondeur moyenne (m) + 0.23 // Hauteur de chute (m) + ) + ); + + const rectStructPrms = new RectangularStructureParams( + 0.773, // Q + 76.67, // ZDV + 0, // Z1 + 0, // Z2 + 0.35, // L + 0.65 // Cd pour un seuil rectangulaire + // W = Infinity par défaut pour un seuil + ); + + // Ajout d'ouvrage dans la cloison + modelCloisons.addChild(new StructureWeirSubmergedLarinier(rectStructPrms)); + modelCloisons.calculatedParam = modelCloisons.prms.Z1; + const res = modelCloisons.CalcSerie(); + expect(res.vCalc).toBeCloseTo(78.27, 2); + expect(res.extraResults.PV).toBeCloseTo(150.03, 2); + }); + }); + }); diff --git a/spec/structure/functions.ts b/spec/structure/functions.ts index 65863fbd5f7be392c62905cf5dd0a7b8607eb854..cb7dfc4dac08ba17787efb750177e8d98a01170a 100644 --- a/spec/structure/functions.ts +++ b/spec/structure/functions.ts @@ -95,6 +95,17 @@ export function testStructure( export function testParallelStructures(oPS: ParallelStructure, iLoiDebits: number[]) { oPS.prms.Q.v = oPS.Calc("Q").vCalc; + // Mémorisation des valeurs initiales pour les références + for (const prm of oPS.prms) { + prm.currentValue = prm.v; + } + for (const st of oPS.structures) { + for (const prm of st.prms) { + prm.currentValue = prm.v; + } + } + + // Tests sur tous les ouvrages for (let i = 0; i < oPS.structures.length; i++) { const st: Structure = oPS.structures[i]; describe(`this.structures[${i}]: Structure${LoiDebit[iLoiDebits[i]]}: `, () => { @@ -113,7 +124,8 @@ export function testParallelStructures(oPS: ParallelStructure, iLoiDebits: numbe prm.calculability === ParamCalculability.DICHO && prm.symbol !== "Z1" && prm.symbol !== "Z2" ) { - const ref: number = prm.v; + const ref: number = prm.currentValue; + prm.v += 100; // Pour éviter de donner la bonne solution en valeur initiale if (prm.symbol === "W" && prm.v === Infinity) { // Le calcul de l'ouverture sur les seuils doit renvoyer une exception (cas impossible) it(`Calc(${prm.symbol}) should return exception`, () => { diff --git a/spec/structure/parallel_structure.spec.ts b/spec/structure/parallel_structure.spec.ts index a473e54cfed2ff39ac5cba2a01c7b619ffe90a7e..8a01b1d2014e232fa97f1147a6ae49803962326f 100644 --- a/spec/structure/parallel_structure.spec.ts +++ b/spec/structure/parallel_structure.spec.ts @@ -18,35 +18,36 @@ import { checkResult } from "../test_func"; import { testParallelStructures } from "./functions"; import { structTest } from "./structure_test"; -const pstruct: ParallelStructure = new ParallelStructure( - new ParallelStructureParams(30, 30, 15), // Q = 30, Z1 = 30, Z2 = 15 - false // debug -); - -/* - * Tests avec deux structures test identiques - */ +function createEnv() { + const pstruct = new ParallelStructure( + new ParallelStructureParams(30, 30, 15), // Q = 30, Z1 = 30, Z2 = 15 + false // debug + ); + /* + * Tests avec deux structures test identiques + */ + pstruct.addChild(structTest); + pstruct.addChild(structTest); + return pstruct; +} -pstruct.addChild(structTest); -pstruct.addChild(structTest); +let pstruct: ParallelStructure; describe("Class ParallelStructure: ", () => { describe("Calc()", () => { + beforeEach(() => { + pstruct = createEnv(); + }); it("should return 1 result", () => { - const res: Result = pstruct.Calc("Q"); - expect(pstruct.Calc("Q").nbResultElements).toEqual(1); + const p1 = createEnv(); + const res: Result = p1.Calc("Q"); + expect(p1.Calc("Q").nbResultElements).toEqual(1); }); - itParallelStructure("Q", 30, 15); - itParallelStructure("Z1", 30, 15); - itParallelStructure("Z2", 15, 15); - itParallelStructure({ - uid: pstruct.structures[0].uid, - symbol: "ZDV" - }, 0, 15); - itParallelStructure({ - uid: pstruct.structures[1].uid, - symbol: "ZDV" - }, 0, 15); + itParallelStructure(null, "Q", 30, 15); + itParallelStructure(null, "Z1", 30, 15); + itParallelStructure(null, "Z2", 15, 15); + itParallelStructure(0, "ZDV", 0, 15); + itParallelStructure(1, "ZDV", 0, 15); it("shoud return an error Q too high", () => { pstruct.prms.Q.v = 14; const res: Result = pstruct.Calc({ @@ -57,6 +58,16 @@ describe("Class ParallelStructure: ", () => { }); }); }); +function getVarCalc(pstructLoc: ParallelStructure, structIndex: number, sVarCalc: string) : any { + if (structIndex !== null) { + return { + uid: pstructLoc.structures[structIndex].uid, + symbol: sVarCalc + }; + } else { + return sVarCalc; + } +} /** * Test sur ParallelStructure @@ -64,25 +75,30 @@ describe("Class ParallelStructure: ", () => { * @param rVcalc Valeur de référence à retrouver * @param Q Débit de chacune des structures (pour structures identiques uniquement) */ -function itParallelStructure(sVarCalc: any, rVcalc: number, Q?: number) { +function itParallelStructure(structIndex: number, sVarCalc: string, rVcalc: number, Q?: number) { it(`${sVarCalc} should be ${rVcalc}`, () => { - checkResult(pstruct.Calc(sVarCalc), rVcalc); + const VC1: any = getVarCalc(pstruct, structIndex, sVarCalc); + checkResult(pstruct.Calc(VC1), rVcalc); }); if (Q !== undefined) { - for (let i = 0; i < pstruct.structures.length; i++) { - it(`ExtraResult[ouvrage[${i}].Q] should be ${Q}`, () => { + const pstructLocal = createEnv(); + for (let i = 0; i < pstructLocal.structures.length; i++) { + it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q] should be ${Q}`, () => { + const VC2: any = getVarCalc(pstruct, structIndex, sVarCalc); expect( - pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q`] + pstruct.Calc(VC2).resultElement.extraResults[`ouvrage[${i}].Q`] ).toBeCloseTo(Q, Math.max(0, precDigits - 1)); }); - it(`ExtraResult[ouvrage[${i}].Q_Mode] should be 0`, () => { + it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q_Mode] should be 0`, () => { + const VC3 = getVarCalc(pstruct, structIndex, sVarCalc); expect( - pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowMode`] + pstruct.Calc(VC3).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowMode`] ).toEqual(0); }); - it(`ExtraResult[ouvrage[${i}].Q_Regime] should be 0`, () => { + it(`Calc(${JSON.stringify(sVarCalc)}) ExtraResult[ouvrage[${i}].Q_Regime] should be 0`, () => { + const VC4 = getVarCalc(pstruct, structIndex, sVarCalc); expect( - pstruct.Calc(sVarCalc).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowRegime`] + pstruct.Calc(VC4).resultElement.extraResults[`ouvrage[${i}].Q_ENUM_StructureFlowRegime`] ).toEqual(0); }); } diff --git a/spec/structure/structure_test.ts b/spec/structure/structure_test.ts index d574a9fa1a561fbd6f4b4f96e8318ab198b7bf57..225bc0fd6d5849c811a2253bd985896981a5af71 100644 --- a/spec/structure/structure_test.ts +++ b/spec/structure/structure_test.ts @@ -31,9 +31,8 @@ class StructureTest extends Structure { return this.getFlowRegime(); } - public Equation(sVarCalc: string): Result { + public CalcQ(): Result { this.prms.update_h1h2(); - Structure.CheckEquation(sVarCalc); const data = this.getResultData(); return new Result(this.prms.Z1.v - this.prms.Z2.v - this.prms.ZDV.v, this, data); diff --git a/spec/value_ref/value_ref.spec.ts b/spec/value_ref/value_ref.spec.ts index c07d15df38100e24403282aca46a88343773331c..c101298864c894401e8b4b5257bdcbbba19af3a5 100644 --- a/spec/value_ref/value_ref.spec.ts +++ b/spec/value_ref/value_ref.spec.ts @@ -6,7 +6,7 @@ */ // import { describe, expect, it } from "../mock_jasmine"; -import { Result, Session } from "../../src/index"; +import { Result, Session, ParamValueMode } from "../../src/index"; import { NubTest, NubTestParams } from "../nubtest"; import { precDigits } from "../test_config"; @@ -42,15 +42,16 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.A.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "A"); - expect(prm1.A.v).toEqual(1); - expect(prm1.B.v).toEqual(2); - expect(prm1.C.v).toEqual(3); - expect(prm2.A.v).toEqual(1); - expect(prm2.B.v).toEqual(2); - expect(prm2.C.v).toEqual(3); + expect(prm1.A.singleValue).toEqual(1); + expect(prm1.B.singleValue).toEqual(2); + expect(prm1.C.singleValue).toEqual(3); + expect(prm2.A.singleValue).toEqual(1); + expect(prm2.B.singleValue).toEqual(2); + expect(prm2.C.singleValue).toEqual(3); }); it("test 2", () => { @@ -60,15 +61,16 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.B.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2) + // valeur esclave, doit être masquée par la valeur maître (cad prm1.B, normalement 2) + prm2.B.singleValue = 0; prm2.B.defineReference(nub1, "B"); - expect(prm1.A.v).toEqual(1); - expect(prm1.B.v).toEqual(2); - expect(prm1.C.v).toEqual(3); - expect(prm2.A.v).toEqual(1); - expect(prm2.B.v).toEqual(2); - expect(prm2.C.v).toEqual(3); + expect(prm1.A.singleValue).toEqual(1); + expect(prm1.B.singleValue).toEqual(2); + expect(prm1.C.singleValue).toEqual(3); + expect(prm2.A.singleValue).toEqual(1); + expect(prm2.B.singleValue).toEqual(2); + expect(prm2.C.singleValue).toEqual(3); }); it("test 3", () => { @@ -78,18 +80,19 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.C.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.C.singleValue = 0; prm2.C.defineReference(nub1, "C"); // as C is a calculated param nub2.triggerChainCalculation(); - expect(prm1.A.v).toEqual(1); - expect(prm1.B.v).toEqual(2); - expect(prm1.C.v).toEqual(3); - expect(prm2.A.v).toEqual(1); - expect(prm2.B.v).toEqual(2); - expect(prm2.C.v).toEqual(3); + expect(prm1.A.singleValue).toEqual(1); + expect(prm1.B.singleValue).toEqual(2); + expect(prm1.C.singleValue).toEqual(3); + expect(prm2.A.singleValue).toEqual(1); + expect(prm2.B.singleValue).toEqual(2); + expect(prm2.C.singleValue).toEqual(3); }); it("test 4", () => { @@ -99,7 +102,8 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.A.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + // valeur esclave, doit être masquée par la valeur maître (cad prm1.A, normalement 1) + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "A"); expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits); @@ -118,18 +122,18 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm1.B.v = 3; // valeur maître - prm2.B.v = 0; // valeur esclave (doit être masquée par la valeur maître) + prm1.B.singleValue = 3; // valeur maître + prm2.B.singleValue = 0; // valeur esclave (doit être masquée par la valeur maître) prm2.B.defineReference(nub1, "B"); - expect(nub1.Calc("A").vCalc).toBeCloseTo(0, precDigits); - expect(nub1.Calc("B").vCalc).toBeCloseTo(3, precDigits); - expect(nub1.Calc("C").vCalc).toBeCloseTo(3, precDigits); + expect(nub1.CalcSerie(undefined, "A").vCalc).toBeCloseTo(0, precDigits); + expect(nub1.CalcSerie(undefined, "B").vCalc).toBeCloseTo(2, precDigits); + expect(nub1.CalcSerie(undefined, "C").vCalc).toBeCloseTo(4, precDigits); + + expect(nub2.CalcSerie(undefined, "A").vCalc).toBeCloseTo(0, precDigits); + expect(nub2.CalcSerie(undefined, "B").vCalc).toBeCloseTo(2, precDigits); + expect(nub2.CalcSerie(undefined, "C").vCalc).toBeCloseTo(4, precDigits); - expect(nub2.Calc("A").vCalc).toBeCloseTo(0, precDigits); - // tslint:disable-next-line:max-line-length - // expect(nub2.Calc("B").vCalc).toBeCloseTo(3, precDigits); // échoue car l'écriture du paramètre esclave (pendant la dichotomie) n'affecte pas la valeur maître; la relecture du paramètre esclave ne reflète pas la valeur écrite - expect(nub2.Calc("C").vCalc).toBeCloseTo(3, precDigits); }); it("test 6", () => { @@ -139,7 +143,8 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.C.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + // valeur esclave, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.C.singleValue = 0; prm2.C.defineReference(nub1, "C"); expect(nub1.Calc("A").vCalc).toBeCloseTo(1, precDigits); @@ -160,15 +165,16 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm1.B.v = 5; + prm1.B.singleValue = 5; nub1.calculatedParam = prm1.C; - prm2.A.v = 0; // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3) + // valeur esclave (doit être masquée par la valeur maître, cad prm1.C, normalement 3) + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "C"); // as C is a calculated param nub2.triggerChainCalculation(); - expect(prm2.A.v).toBeCloseTo(6, precDigits); + expect(prm2.A.singleValue).toBeCloseTo(6, precDigits); }); it("test 2", () => { @@ -178,16 +184,14 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm1.C.v = 0; // valeur bidon, doit être 3 après calcul + prm1.C.singleValue = 0; // valeur bidon, doit être 3 après calcul nub1.calculatedParam = prm1.C; - prm2.C.v = 0; // valeur bidon, doit être 5 après calcul - prm2.A.v = 0; // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.C.singleValue = 0; // valeur bidon, doit être 5 après calcul + // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.C, normalement 3) + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "C"); - // as C is a calculated param - nub2.triggerChainCalculation(); - - expect(nub2.Calc("C").vCalc).toBeCloseTo(5, precDigits); + expect(nub2.CalcSerie(undefined, "C").vCalc).toBeCloseTo(5, precDigits); }); it("test 3", () => { @@ -204,7 +208,7 @@ describe("référence d'un paramètre à un autre : ", () => { prm1.A.setValues(min, max, step); // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [1,2,3,4,5]) - prm2.A.v = 0; + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "A"); let n = 0; @@ -228,9 +232,9 @@ describe("référence d'un paramètre à un autre : ", () => { prm1.A.setValues(input); // valeur esclave bidon, doit être masquée par la valeur maître (cad prm1.A, normalement [2,3,4,5,6]) - prm2.A.v = 0; + prm2.A.singleValue = 0; prm2.A.defineReference(nub1, "A"); - prm2.Pr.v = 0.001; + prm2.Pr.singleValue = 0.001; const r: Result = nub2.CalcSerie(0.1, "C"); diff --git a/spec/value_ref/value_ref_indirect.spec.ts b/spec/value_ref/value_ref_indirect.spec.ts index 9e59d8766dd39005dfd4c3552296be7ae27eb6b2..aca3ba20d54efab48f4e95bc6fe2a572a1bf8212 100644 --- a/spec/value_ref/value_ref_indirect.spec.ts +++ b/spec/value_ref/value_ref_indirect.spec.ts @@ -29,14 +29,14 @@ let prm4: DeverParams; function createEnv() { // Nub 1 : Régime Uniforme const paramSect = new ParamsSectionCirc(2, 0.6613, 40, 1.2, 0.001, 1); - paramSect.Pr.v = 0.01; + paramSect.Pr.singleValue = 0.01; const sect = new cSnCirc(paramSect); nub1 = new RegimeUniforme(sect); prm1 = nub1.section.prms as ParamsSectionCirc; // Nub 2 : Section Paramétrée const prmsS = new ParamsSectionTrapez(1, 0.5, 1, 0.01, 1, 0.01, 2); - prmsS.Pr.v = 0.01; + prmsS.Pr.singleValue = 0.01; nub2 = new SectionParametree(new cSnTrapez(prmsS)); prm2 = nub2.section.prms as ParamsSectionTrapez; // = prmsS @@ -46,7 +46,7 @@ function createEnv() { // Nub 4 : Déversoirs Dénoyés prm4 = new DeverParams(0.5, 102, 10, 99); - prm4.Pr.v = 0.01; + prm4.Pr.singleValue = 0.01; nub4 = new Dever(prm4); nub4.addChild( CreateStructure( @@ -72,7 +72,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm3.Y.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) + prm3.Y.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) prm3.Y.defineReference(nub2.section, "Y"); prm2.Y.defineReference(nub1.section, "Y"); @@ -88,7 +88,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm3.Y.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) + prm3.Y.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) prm3.Y.defineReference(nub2.section, "Y"); prm2.Y.defineReference(nub1.section, "Y"); prm1.Y.setValues(2, 5, 1); @@ -105,12 +105,11 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm3.Y.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) + prm3.Y.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) prm3.Y.defineReference(nub2.section, "Y"); prm2.Y.defineReference(nub1.section, "Y"); - prm1.LargeurBerge.v = 3.5; // Section Circ ! - prm1.Ks.v = 42; + prm1.Ks.singleValue = 42; nub1.calculatedParam = prm1.Y; nub3.CalcSerie(); @@ -125,12 +124,12 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm3.Y.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) + prm3.Y.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm1.Y) prm3.Y.defineReference(nub2.section, "Y"); prm2.Y.defineReference(nub1.section, "Y"); prm1.D.setValues(2.5, 7, 0.5); - prm1.Ks.v = 42; + prm1.Ks.singleValue = 42; nub1.calculatedParam = prm1.Y; nub3.CalcSerie(); @@ -154,7 +153,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm1.Q.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q) + prm1.Q.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q) prm1.Q.defineReference(nub2.section, "Q"); nub1.calculatedParam = prm1.Ks; prm2.Q.defineReference(nub4, "CvQT"); @@ -173,7 +172,7 @@ describe("référence indirecte d'un paramètre à un autre : ", () => { createEnv(); - prm1.Q.v = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q) + prm1.Q.singleValue = 0.1; // valeur esclave, doit être masquée par la valeur maître (cad prm4.Q) prm1.Q.defineReference(nub2.section, "Q"); nub1.calculatedParam = prm1.Ks; prm2.Q.defineReference(nub4, "CvQT"); diff --git a/spec/value_ref/value_ref_section.spec.ts b/spec/value_ref/value_ref_section.spec.ts index 50c1d19e6419ec62779b975ed7799bed2bc2b25c..4dec46b616240f2baf4b5511b19816800cba6f2a 100644 --- a/spec/value_ref/value_ref_section.spec.ts +++ b/spec/value_ref/value_ref_section.spec.ts @@ -51,12 +51,12 @@ describe("référence d'un paramètre à un autre : ", () => { createEnv(); - prm2.Q.v = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.CvQT) + prm2.Q.singleValue = 0; // valeur esclave, doit être masquée par la valeur maître (cad prm1.CvQT) prm2.Q.defineReference(nub1, "CvQT"); - nub2.CalcSerie(); + nub2.CalcSerie(); // triggers chain calculation - expect(prm2.Q.v).toBeCloseTo(10.106); + expect(prm2.Q.singleValue).toBeCloseTo(10.106); }); }); }); diff --git a/src/base.ts b/src/base.ts index be98cf9a14d653128998caeb00d1e356552eba97..9b0c9494aa93512cf67456824b205ea8f23498ec 100644 --- a/src/base.ts +++ b/src/base.ts @@ -63,3 +63,42 @@ export function isNumeric(s: string): boolean { } return false; } + +/** + * Retourne true si a et b sont égaux à e près (en gros) + */ +export function isEqual(a: number, b: number, e: number = 1E-7): boolean { + if (a === 0 && b === 0) { + return true; + } + if (b === 0) { // ne pas diviser par 0 + [ a, b ] = [ b, a ]; + } + if (a === 0) { // éviter d'avoir un quotient toujours nul + return (Math.abs(b) < e); + } + // cas général + return (Math.abs((a / b) - 1) < e); +} + +/** + * Division entière de a par b, plus modulo, avec une tolérance e + * pour gérer le cas des nombres réels + */ +export function floatDivAndMod(a: number, b: number, e: number = 1E-7): { q: number, r: number } { + let q = Math.floor(a / b); + let r = a % b; + // si le modulo est bon à un pouïème, pas de reste + if (isEqual(r, b)) { + r = 0; + // si la division entière n'est pas tombée juste, +1 au quotient + if (q !== (a / b)) { + q++; + } + } + // si le modulo est nul à un pouïème, il est nul + if (isEqual(r, 0)) { + r = 0; + } + return { q, r }; +} diff --git a/src/compute-node.ts b/src/compute-node.ts index 93b34ea7160a4055098335d253f5680507276a32..a49820c6d44b12fa1cb70212cb8ea2f5888d0d65 100644 --- a/src/compute-node.ts +++ b/src/compute-node.ts @@ -17,11 +17,13 @@ export enum CalculatorType { Structure, // ouvrages hydrauliques simples ParallelStructure, // ouvrages hydrauliques en parallèle Dever, // Outil Cassiopée Dever - Cloisons, // Outil Cassiopée PAB Cloisons - MacroRugo, // Passe à enrochement simple (Cassan et al., 2016) + Cloisons, // Outil Cassiopée PAB Cloisons + MacroRugo, // Passe à enrochement simple (Cassan et al., 2016) PabChute, PabNombre, - Section + Section, + Pab, // Passe à bassins; + PabCloisons // modèle de cloisons + débit d'attrait, pour Passe à bassins } /** diff --git a/src/dichotomie.ts b/src/dichotomie.ts index b17acfe1bfd897b7f52ea572e4c3ff058034a1df..edaab56e446f42ec15223afb94ccbb5b15f6484e 100644 --- a/src/dichotomie.ts +++ b/src/dichotomie.ts @@ -159,7 +159,7 @@ export class Dichotomie extends Debug { } private set vX(vCalc: number) { - this._paramX.setValue(vCalc); + this._paramX.v = vCalc; } /** @@ -215,7 +215,7 @@ export class Dichotomie extends Debug { * Il faudra s'assurer que cette première variable correspond à la méthode de calcul la plus rapide */ private Calcul(): Result { - const r: Result = this.nub.Calc(this.analyticalSymbol); + const r: Result = this.nub.Equation(this.analyticalSymbol); this.debug( "dicho : Calcul(vX=" + this.sVarCalc + "=" + this.vX + ") -> " + this.analyticalSymbol + "=" + r.vCalc); diff --git a/src/index.ts b/src/index.ts index a8b1bd974fd57751fccf86d6025d60213bf867b7..2ca952317449ddd2a7e9415090d71f7b4bdfe067 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,7 @@ export * from "./util/interval"; export * from "./util/observer"; export * from "./util/iterator"; export * from "./util/enum"; +export * from "./structure/cloisons"; export * from "./structure/parallel_structure"; export * from "./structure/parallel_structure_params"; export * from "./structure/structure"; @@ -34,3 +35,5 @@ export * from "./linked-value"; export * from "./jalhyd_object"; export * from "./date_revision"; export * from "./section/section_nub"; +export * from "./pab/pab"; +export * from "./pab/pab_cloisons"; diff --git a/src/linked-value.ts b/src/linked-value.ts index 9de169224e6fc016b6e4a57478df2163e78100d0..e1d6a0a3499a807513c4849925529fb0b089fd7b 100644 --- a/src/linked-value.ts +++ b/src/linked-value.ts @@ -3,7 +3,6 @@ import { ParamDefinition } from "./param/param-definition"; import { INamedIterableValues } from "./param/param-value-iterator"; import { ParamValueMode } from "./param/param-value-mode"; import { ParamValues } from "./param/param-values"; -import { Message, MessageCode } from "./util/message"; export class LinkedValue { /** linked value metadata (ex: calculator title for GUI) */ @@ -134,10 +133,6 @@ export class LinkedValue { if (targetParam.hasMultipleValues) { const multipleRes = this.nub.result.getCalculatedValues(); this._paramValues.setValues(multipleRes); - if (this._paramValues.currentValue === undefined) { - // or else isDefined() will return false - this._paramValues.currentValue = multipleRes[0]; - } } else { const singleRes = this.nub.result.vCalc; this._paramValues.setValues(singleRes); @@ -146,9 +141,6 @@ export class LinkedValue { // return local cache ret = this._paramValues; } else { - // else simple parameter proxy (see below) - // @TODO why ? risk of getting obsolete values ! - // ret = targetParam.paramValues; throw new Error("LinkedValue.getParamValues() - result not available"); } @@ -169,10 +161,6 @@ export class LinkedValue { if (this.nub.resultHasMultipleValues()) { const multipleExtraRes = this.nub.result.getExtraResults(this.symbol); this._paramValues.setValues(multipleExtraRes); - if (this._paramValues.currentValue === undefined) { - // or else isDefined() will return false - this._paramValues.currentValue = multipleExtraRes[0]; - } } else { const singleExtraRes = this.nub.result.getExtraResult(this.symbol); this._paramValues.setValues(singleExtraRes); @@ -192,33 +180,12 @@ export class LinkedValue { } /** - * Returns the current value of this.paramValues; triggers a chain computation - * if required to obtain ParamValues; throws an error if this.paramValues is - * ultimately not defined + * Returns the single value of this.paramValues; triggers a chain computation + * if required to obtain ParamValues */ public getValue(triggerChainComputation: boolean = false) { const pv = this.getParamValues(triggerChainComputation); - if (! pv.isDefined) { - const e = new Message(MessageCode.ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED); - e.extraVar.symbol = this.symbol; - throw e; - } - return pv.currentValue; - } - - /** - * Returns the current multiple values list of this.paramValues; triggers a - * chain computation if required to obtain ParamValues; throws an error if - * this.paramValues is ultimately not defined - */ - public getValues(triggerChainComputation: boolean = false): number[] { - const pv = this.getParamValues(triggerChainComputation); - if (! pv.isDefined) { - const e = new Message(MessageCode.ERROR_PARAMDEF_LINKED_VALUE_UNDEFINED); - e.extraVar.symbol = this.symbol; - throw e; - } - return pv.valueList; + return pv.singleValue; } /** @@ -236,6 +203,17 @@ export class LinkedValue { return false; } + /** + * Returns true if target value is available + */ + public isDefined() { + if (this.isExtraResult()) { + return (this.nub.result !== undefined); + } else { + return (this.element as ParamDefinition).isDefined; + } + } + /** * When invalidating a Nub's result, parameters pointing to this result should * invalidate their proxy paramValues too diff --git a/src/nub.ts b/src/nub.ts index d6132a92cbb2e0651bdac96817b6c4f84805359d..b53b73f6a6cfdb1216435f883419d178ad1b279c 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -1,7 +1,7 @@ import { CalculatorType, ComputeNode } from "./compute-node"; // nghyd build fails when commenting CalculatorType @WTF import { Dichotomie } from "./dichotomie"; -import { acSection, IParamDefinitionIterator, ParamDefinition, ParamsEquation, ParamsEquationArrayIterator, - Session, Structure } from "./index"; +import { acSection, IParamDefinitionIterator, Pab, ParamDefinition, ParamsEquation, + ParamsEquationArrayIterator, Session, Structure } from "./index"; import { LinkedValue } from "./linked-value"; import { ParamCalculability } from "./param/param-definition"; import { ParamValueMode } from "./param/param-value-mode"; @@ -256,7 +256,7 @@ export abstract class Nub extends ComputeNode implements IObservable { return this._result; } const sAnalyticalPrm: string = this.getFirstAnalyticalParameter().symbol; - computedVar.setValue(resSolve.vCalc); + computedVar.v = resSolve.vCalc; const res: Result = this.Equation(sAnalyticalPrm); res.vCalc = resSolve.vCalc; this._result = res; @@ -298,8 +298,10 @@ export abstract class Nub extends ComputeNode implements IObservable { this.progress = 0; this.triggerChainCalculation(); + this.copySingleValuesToSandboxValues(); + + // check which values are variating, if any for (const p of this.parameterIterator) { - // checks which values are variating, if any switch (p.valueMode) { case ParamValueMode.SINGLE: case ParamValueMode.CALCUL: @@ -360,7 +362,8 @@ export abstract class Nub extends ComputeNode implements IObservable { variatedValues.initValuesIterator(false); while (variatedValues.hasNext) { - variatedValues.next(); + const currentIteratorValue = variatedValues.next(); + variatedParam.v = currentIteratorValue.value; // copy to local sandbox value this.Calc(computedSymbol, rInit); // résultat dans this._result if (this._result.ok) { @@ -411,6 +414,8 @@ export abstract class Nub extends ComputeNode implements IObservable { child.parent = this; // propagate precision child.prms.Pr.setValue(this.prms.Pr.v); // does not write to .v to bypass calculability control + // postprocessing + this.adjustChildParameters(child); } public getChildren(): Nub[] { @@ -469,7 +474,10 @@ export abstract class Nub extends ComputeNode implements IObservable { // trick to expose p a a result of the parent Nub res.push(new LinkedValue(this.parent, p, p.symbol)); } else { - res.push(new LinkedValue(this, p, p.symbol)); + // do not suggest parameters that are already linked to another one + if (p.valueMode !== ParamValueMode.LINK) { + res.push(new LinkedValue(this, p, p.symbol)); + } } } } @@ -492,9 +500,11 @@ export abstract class Nub extends ComputeNode implements IObservable { } } - // 3. children Nubs - for (const cn of this.getChildren()) { - res = res.concat(cn.getLinkableValues(src)); + // 3. children Nubs, except for PAB + if (! (this instanceof Pab)) { + for (const cn of this.getChildren()) { + res = res.concat(cn.getLinkableValues(src)); + } } return res; @@ -790,7 +800,7 @@ export abstract class Nub extends ComputeNode implements IObservable { } } // define calculated param at Nub level - // @TODO except if we are a Section or Structure ? + // @TODO except if we are a Section / Structure / PabCloisons ? if (calculatedParam) { this.calculatedParam = calculatedParam; } @@ -882,6 +892,8 @@ export abstract class Nub extends ComputeNode implements IObservable { } // add reference to parent collection (this) child.parent = this; + // postprocessing + this.adjustChildParameters(child); } /** @@ -937,6 +949,18 @@ export abstract class Nub extends ComputeNode implements IObservable { return false; } + /** + * @return child having the given UID + */ + public getChild(uid: string): Nub { + for (const s of this._children) { + if (s.uid === uid) { + return s; + } + } + return undefined; + } + /** * Moves a child to first position */ @@ -1015,6 +1039,48 @@ export abstract class Nub extends ComputeNode implements IObservable { this._observable.notifyObservers(data, sender); } + /** + * Returns values of parameters and the result of the calculation for the calculated parameter + * @param sVarCalc Symbol of the calculated param + * @param result Result object of the calculation + */ + protected getParamValuesAfterCalc(sVarCalc: string, result: Result): { [key: string]: number } { + const cPrms: { [key: string]: number } = {}; + for (const p of this.parameterIterator) { + if (p.symbol === sVarCalc) { + cPrms[p.symbol] = result.vCalc; + } else { + cPrms[p.symbol] = p.v; + } + } + return cPrms; + } + + /** + * For all SINGLE, LINK and CALC parameters, copies singleValue to + * sandbox value (.v) before calculation + */ + protected copySingleValuesToSandboxValues() { + for (const p of this.parameterIterator) { + switch (p.valueMode) { + case ParamValueMode.SINGLE: + case ParamValueMode.CALCUL: + p.v = p.singleValue; + break; + case ParamValueMode.LINK: + if (p.referencedValue) { + p.v = p.referencedValue.getValue(); + } else { + throw Error("Nub.CalcSerie() : linked value not defined"); + } + break; + default: + // variable mode, let iterator do the job + p.v = undefined; + } + } + } + /** * To call Nub.calc(…) from indirect child */ @@ -1053,6 +1119,12 @@ export abstract class Nub extends ComputeNode implements IObservable { }, this); } + /** + * Optional postprocessing after adding / replacing a child + */ + // tslint:disable-next-line:no-empty + protected adjustChildParameters(child: Nub) {} + /** * Résoud l'équation par une méthode numérique * @param sVarCalc nom de la variable à calculer diff --git a/src/pab/pab.ts b/src/pab/pab.ts new file mode 100644 index 0000000000000000000000000000000000000000..39c9b0467405363c2b889a90fc7bcdc4c578478a --- /dev/null +++ b/src/pab/pab.ts @@ -0,0 +1,166 @@ +import { CalculatorType } from "../compute-node"; +import { Nub } from "../nub"; +import { ParamCalculability } from "../param/param-definition"; +import { Session } from "../session"; +import { ParallelStructure } from "../structure/parallel_structure"; +import { Result } from "../util/result"; +import { PabCloisons } from "./pab_cloisons"; +import { PabParams } from "./pab_params"; + +export { PabParams }; + +export class Pab extends Nub { + + /** + * Last wall at downstream + */ + public downWall: ParallelStructure; + + constructor(prms: PabParams, downWall: ParallelStructure, dbg: boolean = false) { + super(prms, dbg); + this.downWall = downWall; + this._calcType = CalculatorType.Pab; + } + + /** + * paramètres castés au bon type + */ + get prms(): PabParams { + return this._prms as PabParams; + } + + /** + * enfants castés au bon type + */ + get children(): PabCloisons[] { + return this._children as PabCloisons[]; + } + + public Calc(sVarCalc?: string, rInit?: number): Result { + // Update array of PabCloisons with last Models current values + for (const cl of this.children) { + cl.prms.setCurrentValuesFromModel(); + } + return super.Calc(sVarCalc, rInit); + } + + /** + * Calcul analytique + * @warning Should be called by this.Calc only for parameter initialisations + * @param sVarCalc Variable à calculer (Z1 uniquement) + */ + public Equation(sVarCalc: string): Result { + const r: Result = new Result(0, this); + + // Up to down course : discharge distribution and bottom elevation + let Q: number = this.prms.Q.v; // Upstream discharge + // upstream basin apron elevation + let rZRam: number = this.children[0].prms.Z1.currentValue - this.children[0].Yam; + + for (const cl of this.children) { + Q += cl.prms.QA.v; // Discharge in the current basin + rZRam -= cl.prms.DH.currentValue; + } + + // Down to up course : water surface calculation + let Z: number = this.prms.Z2.v; + Z = this.calcCloisonZ1(this.downWall, Q, Z); + this.downWall.result.extraResults.ZRAM = rZRam; + + for (let i = this.children.length - 1; i >= 0; i--) { + + // Initialisations for current cloison + const cl: PabCloisons = this.children[i]; + rZRam += cl.prms.DH.currentValue; + cl.updateZDV(rZRam); + + // Calculation of upstream water elevation + Z = this.calcCloisonZ1(cl, Q, Z); + if (this.debug) { + console.log("Bassin n°" + i); + let s: string = ""; + for (const p of cl.prms) { + // tslint:disable-next-line:no-console + s += p.symbol + " = " + p.v + "; " ; + } + console.log(s); + + for (const c of cl.getChildren()) { + console.log("Ouvrage"); + s = ""; + for (const p of c.prms) { + // tslint:disable-next-line:no-console + s += p.symbol + " = " + p.v; + } + console.log(s); + } + } + Q -= cl.prms.QA.v; + } + + r.vCalc = Z; + return r; + } + + /** + * Finds the ParallelStructure targetted by modelUid and defines it as the current downWall + */ + public setDownWall(modelUid: string) { + this.properties.setPropValue("modeleCloisonAval", modelUid); + const dw = (Session.getInstance().findNubByUid(modelUid) as ParallelStructure); + if (dw) { + this.downWall = dw; + } /* else { + console.error("Pab.setDownWall : cannot find target ParallelStructure"); + } */ + } + + /** + * Once session is loaded, run a second pass on all PabCloisons to + * reinit their target if needed + */ + public fixPAB(obj: any) { + if (obj.children && Array.isArray(obj.children)) { + // Cloisons models + for (const c of obj.children) { + if (c.props.calcType === CalculatorType.PabCloisons) { // who knows ? + const childUid = c.uid; + const targetCloisonsUid = c.props.modeleCloisons; + // find child PabCloisons to relink + const pabCloisons = (this.getChild(childUid) as PabCloisons); + if (pabCloisons) { + pabCloisons.setModel(targetCloisonsUid); + } // else cannot find target + } + } + // Downstream wall + if (obj.props.modeleCloisonAval) { + this.setDownWall(obj.props.modeleCloisonAval); + } + } + } + + /** + * paramétrage de la calculabilité des paramètres + */ + protected setParametersCalculability() { + this.prms.Z1.calculability = ParamCalculability.EQUATION; + this.prms.Z2.calculability = ParamCalculability.DICHO; + this.prms.Q.calculability = ParamCalculability.DICHO; + } + + private calcCloisonZ1(cl: ParallelStructure, Q: number, Z: number): number { + // Initialisations for current cloison + cl.prms.Q.v = Q; + cl.prms.Z2.v = Z; + + // Calculation of upstream water elevation + cl.Calc("Z1"); + + // TODO: Add extraresults: discharge, apron elevation upstream the wall, apron elevation at half basin + cl.result.extraResults.YMOY = cl.prms.Z2.v - cl.result.extraResults.ZRB; + + // Update elevation and discharge for next basin + return cl.prms.Z1.v; + } +} diff --git a/src/pab/pab_chute.ts b/src/pab/pab_chute.ts index e7b41568894db60e8c52a34cdc26069c4a373145..0e1eb454b4cc1f494410069a48e62283bb556108 100644 --- a/src/pab/pab_chute.ts +++ b/src/pab/pab_chute.ts @@ -3,6 +3,7 @@ import { Nub } from "../nub"; import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition"; import { ParamDomainValue } from "../param/param-domain"; import { ParamsEquation } from "../param/params-equation"; +import { Message, MessageCode } from "../util/message"; import { Result } from "../util/result"; export class PabChuteParams extends ParamsEquation { @@ -60,6 +61,13 @@ export class PabChute extends Nub { public Equation(sVarCalc: string): Result { let v: number; + if (! [ "Z1", "Z2" ].includes(sVarCalc) && this.prms.Z1.v <= this.prms.Z2.v) { + const m = new Message(MessageCode.ERROR_ELEVATION_ZI_LOWER_THAN_Z2); + m.extraVar.Z1 = this.prms.Z1.v; + m.extraVar.Z2 = this.prms.Z2.v; + return new Result(m); + } + switch (sVarCalc) { case "Z1": v = this.prms.Z2.v + this.prms.DH.v; diff --git a/src/pab/pab_cloisons.ts b/src/pab/pab_cloisons.ts new file mode 100644 index 0000000000000000000000000000000000000000..aeb74a2dec83aa4a2ae5bf06185548bfc3281f68 --- /dev/null +++ b/src/pab/pab_cloisons.ts @@ -0,0 +1,151 @@ +import { ParamCalculability, ParamDefinition, ParamFamily} from "../param/param-definition"; +import { ParamDomainValue } from "../param/param-domain"; +import { Result } from "../util/result"; + +import { CalculatorType, Session } from "../index"; +import { Cloisons, CloisonsParams } from "../structure/cloisons"; +import { Pab } from "./pab"; + +class PabCloisonsParams extends CloisonsParams { + + /** Débit d'attrait d'un bassin (m3/s) */ + public _QA: ParamDefinition; + + /** Model of cloison on which this pabCloison is based */ + private _modelCloisonsParams: CloisonsParams; + + /** + * Paramètres communs à toutes les équations de structure + * @param rQ Débit total (m3/s) + * @param rZ1 Cote de l'eau amont (m) + * @param rLB Longueur des bassins (m) + * @param rBB Largeur des bassins (m) + * @param rPB Profondeur moyenne (m) + * @param rDH Hauteur de chute (m) + */ + constructor(modelCloisonsParams?: CloisonsParams, rQA: number = 0) { + super(1, 1, 1, 1, 1, 1); // overwritten by init() below + this.modelCloisonsParams = modelCloisonsParams; + + // Débit d'attrait + this._QA = new ParamDefinition(this, "QA", ParamDomainValue.POS_NULL, rQA, ParamFamily.FLOWS); + this.addParamDefinition(this._QA); + } + + public get QA() { + return this._QA; + } + + /** + * Record pointer to the cloison model for future updating of local parameters + */ + set modelCloisonsParams(modelCloisonsParams: CloisonsParams) { + this._modelCloisonsParams = modelCloisonsParams; + } + + /** + * Update Current values and sandobx values of parameter from cloison model + */ + public setCurrentValuesFromModel() { + if (this._modelCloisonsParams !== undefined) { + for (const p of this._modelCloisonsParams) { + this._paramMap[p.symbol].currentValue = p.currentValue; + this._paramMap[p.symbol].v = p.currentValue; + } + } + } + +} + +// tslint:disable-next-line:max-classes-per-file +export class PabCloisons extends Cloisons { + + /** + * paramètres castés au bon type + */ + get prms(): PabCloisonsParams { + return this._prms as PabCloisonsParams; + } + + /** + * Calculation of upstream water depth + */ + get Yam(): number { + // TODO: ajouter l'option radier horizontal + return this.prms.PB.currentValue + this.prms.DH.currentValue / 2; + } + + public parent: Pab; + + constructor(modelCloisons: Cloisons, rQA: number = 0, dbg: boolean = false) { + super(new PabCloisonsParams(), dbg); // model is set below + this.initModelCloisons(modelCloisons); + this._calcType = CalculatorType.PabCloisons; + } + + public Calc(sVarCalc: string, rInit?: number): Result { + const r: Result = super.Calc(sVarCalc, rInit); + const p = this.getParamValuesAfterCalc(sVarCalc, r); + r.extraResults.ZRAM = p.Z1 - p.PB; + return r; + } + + /** + * Update crest elevations from upstream apron elevation + */ + public updateZDV(rZR: number) { + for (const st of this.structures) { + if (st.prms.ZDV.calculability !== ParamCalculability.NONE) { + st.prms.ZDV.v = st.prms.ZDV.currentValue + rZR - (this.prms.Z1.currentValue - this.Yam); + } + } + } + + /** + * Sets modelCloisons as the current model (set pointers to parameters and structure array) + */ + public initModelCloisons(modelCloisons: Cloisons) { + this.prms.modelCloisonsParams = modelCloisons ? modelCloisons.prms : undefined; + this._children = modelCloisons ? modelCloisons.structures : []; + } + + /** + * Finds the Cloisons targetted by modelUid and defines it as the current model + */ + public setModel(modelUid: string) { + this.properties.setPropValue("modeleCloisons", modelUid); + const cloisons = (Session.getInstance().findNubByUid(modelUid) as Cloisons); + if (cloisons) { + this.initModelCloisons(cloisons); + } /* else { + console.error("PabCloisons.setModel : cannot find target Cloisons"); + } */ + } + + /** + * Returns an object representation of the Nub's current state + */ + public objectRepresentation() { + const ret: any = { + uid: this.uid, + props: this.properties.props, + parameters: [] + }; + + // ! do not iterate over local parameters (would copy the parameters of the Cloisons used as model), + // just serialise QA + ret.parameters.push(this.prms.QA.objectRepresentation()); + + // ! do not iterate over children Nubs (would copy the children of the Cloisons used as model) + + return ret; + } + + /** + * paramétrage de la calculabilité des paramètres + */ + protected setParametersCalculability() { + super.setParametersCalculability(); + this.prms._QA.calculability = ParamCalculability.FREE; + } +} diff --git a/src/pab/pab_nombre.ts b/src/pab/pab_nombre.ts index a853df31ee87c3c4fcad2fc950f2f4adc8d85b23..a9c34bc512bea954d6cfb09297d3c350cc06030d 100644 --- a/src/pab/pab_nombre.ts +++ b/src/pab/pab_nombre.ts @@ -1,8 +1,10 @@ +import { floatDivAndMod } from "../base"; import { CalculatorType } from "../compute-node"; import { Nub } from "../nub"; import { ParamCalculability, ParamDefinition, ParamFamily } from "../param/param-definition"; import { ParamDomainValue } from "../param/param-domain"; import { ParamsEquation } from "../param/params-equation"; +import { Message, MessageCode } from "../util/message"; import { Result } from "../util/result"; export class PabNombreParams extends ParamsEquation { @@ -11,7 +13,7 @@ export class PabNombreParams extends ParamsEquation { /** Chute totale DHT */ private _DHT: ParamDefinition; - /** Nombre de bassins N */ + /** Nombre de chutes N */ private _N: ParamDefinition; /** Chute entre bassins DH */ @@ -58,6 +60,12 @@ export class PabNombre extends Nub { } public Equation(sVarCalc: string): Result { + if (sVarCalc !== "N" && ! Number.isInteger(this.prms.N.v)) { + const m = new Message(MessageCode.ERROR_PARAMDEF_VALUE_INTEGER); + m.extraVar.N = this.prms.N.v; + return new Result(m); + } + let v: number; let DHR = 0; @@ -67,8 +75,9 @@ export class PabNombre extends Nub { break; case "N": - v = Math.floor(this.prms.DHT.v / this.prms.DH.v); - DHR = this.prms.DHT.v % this.prms.DH.v; + const divAndMod = floatDivAndMod(this.prms.DHT.v, this.prms.DH.v); + v = divAndMod.q; + DHR = divAndMod.r; break; case "DH": @@ -99,5 +108,4 @@ export class PabNombre extends Nub { DHR: ParamFamily.HEIGHTS }; } - } diff --git a/src/pab/pab_params.ts b/src/pab/pab_params.ts new file mode 100644 index 0000000000000000000000000000000000000000..94d71df2782d9f3f12905b393f04a3170e9cced0 --- /dev/null +++ b/src/pab/pab_params.ts @@ -0,0 +1,33 @@ +import { ParamDefinition, ParamFamily } from "../param/param-definition"; +import { ParamDomainValue } from "../param/param-domain"; +import { ParamsEquation } from "../param/params-equation"; + +/** + * Parameters of a fish ladder + */ +export class PabParams extends ParamsEquation { + + /** Débit entrant à l'amont de la passe (m3/s) */ + public Q: ParamDefinition; + + /** Cote de l'eau amont (m) */ + public Z1: ParamDefinition; + + /** Cote de l'eau aval (m) */ + public Z2: ParamDefinition; + + /** + * Paramètres communs à toutes les équations de structure + * @param rZ1 Cote de l'eau amont (m) + * @param rZ2 Cote de l'eau aval (m) + */ + constructor(rQ: number, rZ1: number, rZ2: number) { + super(); + this.Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ, ParamFamily.FLOWS); + this.addParamDefinition(this.Q); + this.Z1 = new ParamDefinition(this, "Z1", ParamDomainValue.ANY, rZ1, ParamFamily.ELEVATIONS); + this.addParamDefinition(this.Z1); + this.Z2 = new ParamDefinition(this, "Z2", ParamDomainValue.ANY, rZ2, ParamFamily.ELEVATIONS); + this.addParamDefinition(this.Z2); + } +} diff --git a/src/pab/pab_puissance.ts b/src/pab/pab_puissance.ts index 44368c506f899b5fe70f8ca5148ec88d1eaabdfd..460add1fd8cb6897f27756116e70e902bec54c5c 100644 --- a/src/pab/pab_puissance.ts +++ b/src/pab/pab_puissance.ts @@ -23,7 +23,7 @@ export class PabPuissanceParams extends ParamsEquation { constructor(rDH: number, rQ: number, rV: number, rPV?: number) { super(); this._DH = new ParamDefinition(this, "DH", ParamDomainValue.POS, rDH, ParamFamily.HEIGHTS); - this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS, rQ, ParamFamily.FLOWS); + this._Q = new ParamDefinition(this, "Q", ParamDomainValue.POS_NULL, rQ, ParamFamily.FLOWS); this._V = new ParamDefinition(this, "V", ParamDomainValue.POS, rV, ParamFamily.VOLUMES); this._PV = new ParamDefinition(this, "PV", ParamDomainValue.POS, rPV); diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts index 13b100c3b7c605837b1a4c51322a232d588f32c7..fc9b44f5ea2c5b780f66f7046d0e5a3c5f90e3a6 100644 --- a/src/param/param-definition.ts +++ b/src/param/param-definition.ts @@ -50,6 +50,9 @@ export class ParamDefinition implements INamedIterableValues, IObservable { /** le paramètre doit-il être exposé (par ex: affiché par l'interface graphique) ? */ public visible: boolean = true; + /** sandbox value used during calculation */ + public v: number; + /** mode de génération des valeurs : min/max, liste, ... */ private _valueMode: ParamValueMode; @@ -84,7 +87,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable { this._symbol = symb; this._observable = new Observable(); this._paramValues = new ParamValues(); + + // set single value and copy it to currentValue this._paramValues.singleValue = val; + this.v = val; + this._calc = ParamCalculability.FREE; this._family = family; this.visible = visible; @@ -370,74 +377,84 @@ export class ParamDefinition implements INamedIterableValues, IObservable { } /** - * Proxy to getValue(); never triggers chain computation + * Returns true if current value (not singleValue !) is defined */ - get v(): number { - return this.getValue(); + public get hasCurrentValue(): boolean { + return (this.v !== undefined); } /** - * set value, with calculability control - * @TODO move calculability control to setValue() ? + * Returns true if held value (not currentValue !) is defined, + * depending on the value mode */ - set v(val: number) { - if (this.calculability === ParamCalculability.NONE) { - const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_FIXED); - e.extraVar.symbol = this.symbol; - throw e; - } - this.setValue(val); - } - public get isDefined(): boolean { - try { - return this.paramValues.isDefined; - } catch (e) { - // unavailable targetted result (pending calculation) - return false; + let defined = false; + switch (this.valueMode) { + case ParamValueMode.SINGLE: + defined = (this.singleValue !== undefined); + break; + case ParamValueMode.MINMAX: + defined = ( + this.paramValues.min !== undefined + && this.paramValues.max !== undefined + && this.paramValues.step !== undefined + ); + break; + case ParamValueMode.LISTE: + defined = (this.valueList.length > 0 && this.valueList[0] !== undefined); + break; + case ParamValueMode.CALCUL: + if (this.parentNub && this.parentNub.result && this.parentNub.result.nbResultElements > 0) { + const res = this.parentNub.result; + defined = (res.vCalc !== undefined); + } + break; + case ParamValueMode.LINK: + defined = this.referencedValue.isDefined(); } + return defined; } // -- values getters / setters; in LINK mode, reads / writes from / to the target values public get singleValue(): number { - this.checkValueMode(ParamValueMode.SINGLE); + this.checkValueMode([ParamValueMode.SINGLE, ParamValueMode.CALCUL, ParamValueMode.LINK]); return this.paramValues.singleValue; } public set singleValue(v: number) { - this.checkValueMode(ParamValueMode.SINGLE); + this.checkValueMode([ParamValueMode.SINGLE, ParamValueMode.CALCUL, ParamValueMode.LINK]); this.paramValues.singleValue = v; this.notifyValueModified(this); } public get min() { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]); return this.paramValues.min; } public set min(v: number) { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX]); this.paramValues.min = v; } public get max() { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]); return this.paramValues.max; } public set max(v: number) { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX]); this.paramValues.max = v; } public get step() { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX, ParamValueMode.LINK]); return this.paramValues.step; } public set step(v: number) { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX]); this.paramValues.step = v; } @@ -445,17 +462,17 @@ export class ParamDefinition implements INamedIterableValues, IObservable { * Generates a reference step value, given the current (local) values for min / max */ public get stepRefValue(): Interval { - this.checkValueMode(ParamValueMode.MINMAX); + this.checkValueMode([ParamValueMode.MINMAX]); return new Interval(1e-9, this._paramValues.max - this._paramValues.min); } public get valueList() { - this.checkValueMode(ParamValueMode.LISTE); + this.checkValueMode([ParamValueMode.LISTE, ParamValueMode.LINK]); return this.paramValues.valueList; } public set valueList(l: number[]) { - this.checkValueMode(ParamValueMode.LISTE); + this.checkValueMode([ParamValueMode.LISTE]); this.paramValues.valueList = l; } @@ -463,23 +480,22 @@ export class ParamDefinition implements INamedIterableValues, IObservable { return this.paramValues.valuesIterator.count(); } - /** - * Get current value (not singleValue !) - * Might throw an error if parameter is in LINK mode, and target - * value is a result that is not yet computed - */ - public getValue(): number { - if (! this.paramValues.isDefined) { - const e = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED); - e.extraVar.symbol = this.symbol; - throw e; - } + // for INumberiterator interface + public get currentValue(): number { + // magically follows links return this.paramValues.currentValue; } - // for INumberiterator interface - public get currentValue(): number { - return this.getValue(); + public set currentValue(v: number) { + // magically follows links + this.paramValues.currentValue = v; + } + + /** + * Get single value + */ + public getValue(): number { + return this.paramValues.singleValue; } /** @@ -507,7 +523,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable { */ public setValue(val: number, sender?: any) { this.checkValueAgainstDomain(val); - this.paramValues.currentValue = val; + this.paramValues.singleValue = val; // this.notifyValueModified(sender); // @TODO why ? currentValue is only used temporarily for calculation } @@ -590,11 +606,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable { } /** - * Return true if current value is valid regarding the domain constraints + * Return true if single value is valid regarding the domain constraints */ get isValueValid(): boolean { try { - const v = this.getValue(); + const v = this.paramValues.singleValue; this.checkValueAgainstDomain(v); return true; } catch (e) { @@ -760,7 +776,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable { // adjust parameter representation depending on value mode switch (this._valueMode) { case ParamValueMode.SINGLE: - paramRep.value = this.getValue(); + paramRep.value = this.singleValue; break; case ParamValueMode.MINMAX: @@ -1100,9 +1116,11 @@ export class ParamDefinition implements INamedIterableValues, IObservable { * In LINK mode, the tested valueMode is the mode of the ultimately targetted * set of values (may never be LINK) */ - private checkValueMode(expected: ParamValueMode) { - if (this.paramValues.valueMode !== expected) { - throw new Error(`ParamValues : mode de valeurs ${ParamValueMode[expected]} incorrect`); + private checkValueMode(expected: ParamValueMode[]) { + if (! expected.includes(this.valueMode)) { + throw new Error( + `ParamDefinition : mode de valeurs ${ParamValueMode[this.valueMode]} incorrect` + ); } } diff --git a/src/param/param-values.ts b/src/param/param-values.ts index badb8433f819f721766be6945e081e18fbbf2842..9d850c7d16bcf7c042d6e4f298ac74bf15b6b37b 100644 --- a/src/param/param-values.ts +++ b/src/param/param-values.ts @@ -54,18 +54,15 @@ export class ParamValues implements IterableValues { if (max === undefined) { this.valueMode = ParamValueMode.SINGLE; this.singleValue = o; - this.currentValue = o; } else { this.valueMode = ParamValueMode.MINMAX; this.min = o; this.max = max; this.step = step; - this.currentValue = undefined; } } else if (Array.isArray(o)) { this.valueMode = ParamValueMode.LISTE; this.valueList = o; - this.currentValue = undefined; } else { throw new Error(`ParamValues.setValues() : appel invalide`); } @@ -107,10 +104,6 @@ export class ParamValues implements IterableValues { } } - public get isDefined() { - return this.currentValue !== undefined; - } - // -- iterator-related methods /** diff --git a/src/param/params-equation.ts b/src/param/params-equation.ts index 5e13164f33b44d5d0603d38f8134a2c7eb96f232..91a81b7115b5f5c9665d7e937171331a44675fe9 100644 --- a/src/param/params-equation.ts +++ b/src/param/params-equation.ts @@ -104,7 +104,9 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> { public constructor(parent?: ComputeNode) { this.parent = parent; this._calculabilityDefined = false; - this._Pr = new ParamDefinition(this, "Pr", ParamDomainValue.POS, ParamsEquation.DEFAULT_COMPUTE_PREC); + this._Pr = new ParamDefinition( + this, "Pr", ParamDomainValue.POS, ParamsEquation.DEFAULT_COMPUTE_PREC, undefined, false + ); this.addParamDefinition(this._Pr); } @@ -168,15 +170,16 @@ export abstract class ParamsEquation implements Iterable<ParamDefinition> { return new ParamDefinitionIterator(this); } - protected addParamDefinition(p: ParamDefinition) { - if (!this.hasParameter(p.symbol)) { + protected addParamDefinition(p: ParamDefinition, force: boolean = false) { + if (force || !this.hasParameter(p.symbol)) { this._paramMap[p.symbol] = p; } } protected addParamDefinitions(ps: ParamsEquation) { for (const p of ps) { - this.addParamDefinition(p); + // Force update of the map index + this.addParamDefinition(p, true); } } } diff --git a/src/regime_uniforme.ts b/src/regime_uniforme.ts index 4a349f3b3bc65450607f4c274a65a5485f6606ef..bf0685c50bf4fd037095904e68cd806e2991fdac 100644 --- a/src/regime_uniforme.ts +++ b/src/regime_uniforme.ts @@ -50,7 +50,7 @@ export class RegimeUniforme extends SectionNub { // tslint:disable-next-line:no-empty protected setParametersCalculability() {} - protected setSectionParametersCalculability(): void { + protected adjustChildParameters(): void { this.section.prms.Q.calculability = ParamCalculability.EQUATION; this.section.prms.Y.calculability = ParamCalculability.EQUATION; } diff --git a/src/remous.ts b/src/remous.ts index 234c1d8a7a8359cc070d0848c8e0e263ef1915cf..867f3cbf18dab2f062e923a10e63f12ad2c4a817 100644 --- a/src/remous.ts +++ b/src/remous.ts @@ -519,7 +519,7 @@ export class CourbeRemous extends SectionNub { this.prms.Yaval.calculability = ParamCalculability.FREE; } - protected setSectionParametersCalculability(): void { + protected adjustChildParameters(): void { this.section.prms.Y.calculability = ParamCalculability.DICHO; } diff --git a/src/section/section_circulaire.ts b/src/section/section_circulaire.ts index 4ff68af501fbcdcc70f02a0985eb0d4d341e4d1e..af68e902e0e87710bff49ebcfb450b4a9790135b 100644 --- a/src/section/section_circulaire.ts +++ b/src/section/section_circulaire.ts @@ -92,7 +92,7 @@ export class cSnCirc extends acSection { } this.debug("circ.Calc_B() : PAS débordement"); - if (this.prms.D.isDefined && this.prms.Y.isDefined) { + if (this.prms.D.hasCurrentValue && this.prms.Y.hasCurrentValue) { const rAlpha: Result = this.calcFromY("Alpha"); if (!rAlpha.ok) { return rAlpha; @@ -104,8 +104,8 @@ export class cSnCirc extends acSection { } const e: Message = new Message(MessageCode.ERROR_PARAMDEF_VALUE_UNDEFINED); - e.extraVar.diameterValue = this.prms.D.isDefined ? String(this.prms.D.v) : "undefined"; - e.extraVar.yValue = this.prms.Y.isDefined ? String(this.prms.Y.v) : "undefined"; + e.extraVar.diameterValue = this.prms.D.hasCurrentValue ? String(this.prms.D.v) : "undefined"; + e.extraVar.yValue = this.prms.Y.hasCurrentValue ? String(this.prms.Y.v) : "undefined"; throw e; } diff --git a/src/section/section_nub.ts b/src/section/section_nub.ts index 37cf0dff307d7dec1b6146e5ae072641abb8423e..c53b7cda13a8dd46ba051405868d6fb25932b461 100644 --- a/src/section/section_nub.ts +++ b/src/section/section_nub.ts @@ -96,10 +96,6 @@ export abstract class SectionNub extends Nub { this._children[0] = undefined; } this.replaceChild(0, s); - this.setSectionParametersCalculability(); } } - - /** Called everytime a section is set / replaced */ - protected abstract setSectionParametersCalculability(): void; } diff --git a/src/section/section_parametree.ts b/src/section/section_parametree.ts index 874418aac3269a0ab419e75721bcf13c4a201c84..b3d03d8d4c561d9eaa828adfb44717ea539d9a24 100644 --- a/src/section/section_parametree.ts +++ b/src/section/section_parametree.ts @@ -202,7 +202,7 @@ export class SectionParametree extends SectionNub { protected setParametersCalculability(): void {} // tslint:disable-next-line:no-empty - protected setSectionParametersCalculability(): void {} + protected adjustChildParameters(): void {} protected setExtraResultsFamilies() { this._extraResultsFamilies = { diff --git a/src/session.ts b/src/session.ts index c70f3d5b03dfb63c94ecaf2abc95ef98e973f0f9..8e9b40421bbd4332f890c2c3b6eecacfa1efa52d 100644 --- a/src/session.ts +++ b/src/session.ts @@ -1,4 +1,5 @@ import { CalculatorType, ComputeNodeType } from "./compute-node"; +import { LinkedValue } from "./linked-value"; import { Nub } from "./nub"; import { Props } from "./props"; @@ -22,14 +23,14 @@ import { cSnTrapez, ParamsSectionTrapez } from "./section/section_trapez"; import { acSection } from "./section/section_type"; // Classes relatives aux structures -import { LinkedValue } from "./linked-value"; +import { Pab, PabParams } from "./pab/pab"; +import { PabCloisons } from "./pab/pab_cloisons"; import { ParamDefinition } from "./param/param-definition"; import { Cloisons } from "./structure/cloisons"; import { CloisonsParams } from "./structure/cloisons_params"; import { Dever, DeverParams } from "./structure/dever"; import { CreateStructure } from "./structure/factory_structure"; import { ParallelStructure, ParallelStructureParams } from "./structure/parallel_structure"; -import { Structure } from "./structure/structure"; import { LoiDebit } from "./structure/structure_props"; export class Session { @@ -149,6 +150,9 @@ export class Session { // second pass for links this.fixLinks(serialised, uids); + // second pass for PABs + this.fixPAB(serialised, uids); + return newNubs; } @@ -332,7 +336,7 @@ export class Session { 0.5, // D 0.8, // k 1.5 // Cd0 - ) + ), dbg ); break; } @@ -344,7 +348,7 @@ export class Session { 2, // Z1 0.5, // Z2 1.5 // DH - ) + ), dbg ); break; } @@ -356,7 +360,7 @@ export class Session { 6, // DHT 10, // N 0.6 // DH - ) + ), dbg ); break; } @@ -367,6 +371,33 @@ export class Session { break; } + case CalculatorType.Pab: + const modeleCloisonAval: string = params.getPropValue("modeleCloisonAval"); + let downWall; + if (modeleCloisonAval) { + downWall = (Session.getInstance().findNubByUid(modeleCloisonAval) as ParallelStructure); + // si le module ParallelStructure ciblé n'existe pas, Session.fixPAB() est censé s'en occuper + } + nub = new Pab( + new PabParams( + 1.5, // Q + 102, // Z1 + 99 // Z2 + ), downWall, dbg + ); + break; + + case CalculatorType.PabCloisons: + const modeleCloisons: string = params.getPropValue("modeleCloisons"); + if (modeleCloisons) { + const cloisons = (Session.getInstance().findNubByUid(modeleCloisons) as Cloisons); + // si le module Cloisons ciblé n'existe pas, Session.fixPAB() est censé s'en occuper + nub = new PabCloisons(cloisons); + } else { + nub = new PabCloisons(undefined); // don't forget to init with a Cloisons model afterwards ! + } + break; + default: { throw new Error( @@ -435,6 +466,33 @@ export class Session { return res; } + /** + * Returns all Nubs of type Cloisons, to be used as models in PAB + */ + public getCloisonsNubs() { + const cloisonsNubs: Nub[] = []; + for (const n of this._nubs) { + if (n instanceof Cloisons) { + cloisonsNubs.push(n); + } + } + return cloisonsNubs; + } + + /** + * Returns all Nubs of type ParallelStructure (no sub-types), + * to be used as downWall models in PAB + */ + public getParallelStructureNubs() { + const psNubs: Nub[] = []; + for (const n of this._nubs) { + if (n.constructor === ParallelStructure) { // exact class checking + psNubs.push(n); + } + } + return psNubs; + } + /** * Crée un Nub de type Section * @param nt ComputeNodeType @@ -537,4 +595,24 @@ export class Session { }); } } + + /** + * Asks all loaded PAB Nubs to reinit any PabCloisons from their model + */ + private fixPAB(serialised: string, uids?: string[]) { + const data = JSON.parse(serialised); + if (data.session && Array.isArray(data.session)) { + // find each PAB in the session + data.session.forEach((e: any) => { + if ( + (! uids || uids.length === 0 || uids.includes(e.uid)) + && (e.props.calcType === CalculatorType.Pab) + ) { + const nub = (this.findNubByUid(e.uid) as Pab); + // find linked parameters + nub.fixPAB(e); + } + }); + } + } } diff --git a/src/structure/cloisons.ts b/src/structure/cloisons.ts index bfc110a8e1a665d36a349fe34a86df858d7b816b..54e9c2c5da10447d33c960e97f29711cc316abc5 100644 --- a/src/structure/cloisons.ts +++ b/src/structure/cloisons.ts @@ -1,4 +1,5 @@ import { CalculatorType } from "../compute-node"; +import { Nub } from "../index"; import { PabPuissance, PabPuissanceParams } from "../pab/pab_puissance"; import { ParamCalculability } from "../param/param-definition"; import { Result } from "../util/result"; @@ -7,6 +8,7 @@ import { ParallelStructure } from "./parallel_structure"; import { StructureKiviParams } from "./structure_kivi"; import { loiAdmissiblesCloisons, LoiDebit } from "./structure_props"; +export { CloisonsParams }; export class Cloisons extends ParallelStructure { constructor(prms: CloisonsParams, dbg: boolean = false) { super(prms, dbg); @@ -24,6 +26,16 @@ export class Cloisons extends ParallelStructure { return loiAdmissiblesCloisons; } + public Equation(sVarCalc: string): Result { + // Mise à jour de ZRAM pour Kivi à partir de Z1 - PB + this.updateKiviZRAM(); + + // Transformation DH => Z2 + this.prms.Z2.v = this.prms.Z1.v - this.prms.DH.v; + + return super.Equation(sVarCalc); + } + /** * Calcul du débit total, de la cote amont ou aval ou d'un paramètre d'une structure * @param sVarCalc Nom du paramètre à calculer : @@ -31,33 +43,12 @@ export class Cloisons extends ParallelStructure { * @param rInit Valeur initiale */ public Calc(sVarCalc: string, rInit?: number): Result { - // Mise à jour de ZRAM pour Kivi à partir de Z1 - PB - this.updateKiviZRAM(); - - // Transformation DH => Z2 - this.prms.Z2.v = this.prms.Z1.v - this.prms.DH.v; let sVC: string = sVarCalc; if (sVarCalc === "DH") { sVC = "Z2"; } - // let r: Result = super.Calc(sVC, rInit); - let r: Result; - switch (sVC) { - case "Z1": - case "Z2": - case "Q": - case "LB": - case "PB": - case "BB": - r = this.nubCalc(sVC, rInit); - if (r.ok) { - this.getParameter(sVC).setValue(r.vCalc); - } - break; - default: - r = super.Calc(sVC, rInit); - } + const r: Result = super.Calc(sVC, rInit); if (r.ok) { // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires @@ -75,19 +66,24 @@ export class Cloisons extends ParallelStructure { } // Ajout du calcul de la puissance dissipée - const prms = this.getcalculatedparams(sVarCalc, r); - const puissanceNub: PabPuissance = new PabPuissance( - new PabPuissanceParams( - prms.DH, - prms.Q, - prms.LB * prms.BB * prms.PB - ) - ); - r.extraResults.PV = puissanceNub.Calc("PV", 0).vCalc; + const prms = this.getParamValuesAfterCalc(sVarCalc, r); + const ro: number = 1000; // masse volumique de l'eau en kg/m3 + const g: number = 9.81; // accélération de la gravité terrestre en m/s2. + r.extraResults.PV = ro * g * this.prms.Q.v * (prms.Z1 - prms.Z2) / (prms.LB * prms.BB * prms.PB); + + // Ajout de la cote de radier de bassin + r.extraResults.ZRB = prms.Z1 - prms.DH - prms.PB; return r; } + public adjustChildParameters(child: Nub) { + if (child.prms instanceof StructureKiviParams) { + // hide ZRAM for KIVI, in Cloisons context only + child.prms.ZRAM.visible = false; + } + } + /** * paramétrage de la calculabilité des paramètres */ @@ -99,18 +95,6 @@ export class Cloisons extends ParallelStructure { this.prms.DH.calculability = ParamCalculability.DICHO; } - protected getcalculatedparams(sVarCalc: string, result: Result): { [key: string]: number } { - const cPrms: { [key: string]: number } = {}; - for (const p of this.parameterIterator) { - if (p.symbol === sVarCalc) { - cPrms[p.symbol] = result.vCalc; - } else { - cPrms[p.symbol] = p.v; - } - } - return cPrms; - } - private updateKiviZRAM() { for (const structure of this.structures) { if (structure.prms instanceof StructureKiviParams) { diff --git a/src/structure/dever.ts b/src/structure/dever.ts index fedcf19599084101a75386072526d3feee0eaba2..24cfeb68011b83d1747189374143b08f6ae3a2a7 100644 --- a/src/structure/dever.ts +++ b/src/structure/dever.ts @@ -50,42 +50,6 @@ export class Dever extends ParallelStructure { return r; } - /** - * Calcul du débit total, de la cote amont ou aval, de la largeur du lit amont, de la cote - * du lit amont, ou d'un paramètre d'une structure - * @param sVarCalc Nom du paramètre à calculer : - * "Q", "Z1", "Z2", "BR", "ZR" ou "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre - * @param rInit Valeur initiale - */ - public Calc(sVarCalc: string, rInit?: number): Result { - let res: Result; - switch (sVarCalc) { - case "Z1": - case "Z2": - case "Q": - case "BR": - case "ZR": - res = this.nubCalc(sVarCalc, rInit); - if (res.ok) { - this.getParameter(sVarCalc).setValue(res.vCalc); - } - break; - default: - res = super.Calc(sVarCalc, rInit); - } - if (res.ok) { - // Recalcul du débit total pour récupérer les résultats des ouvrages dans les résultats complémentaires - const resQtot: Result = this.CalcQ(); - for (const extraResKey in resQtot.extraResults) { - if (resQtot.extraResults.hasOwnProperty(extraResKey)) { - res.resultElement.addExtraResult(extraResKey, resQtot.extraResults[extraResKey]); - } - } - } - this._result = res; - return res; - } - /** * paramétrage de la calculabilité des paramètres */ diff --git a/src/structure/factory_structure.ts b/src/structure/factory_structure.ts index e4a9f2b17cdb6dc22b661ee935e3f53d12f9bbe3..48d711d014617ed8b064bf1484dc420248308c64 100644 --- a/src/structure/factory_structure.ts +++ b/src/structure/factory_structure.ts @@ -39,7 +39,7 @@ export function CreateStructure(loiDebit: LoiDebit, parentNub?: ParallelStructur case LoiDebit.Cunge80: case LoiDebit.RectangularOrificeFree: case LoiDebit.RectangularOrificeSubmerged: - rectStructPrms.W.v = 0.5; + rectStructPrms.W.singleValue = 0.5; rectStructPrms.Cd.v = oCd.VanneR; // Cd pour une vanne rectangulaire } diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts index 7b589783e9e8a691e86169891de7852f0fc1e564..2f4f8e32a49a17ff2db8ed51f02d1c95173c2730 100644 --- a/src/structure/parallel_structure.ts +++ b/src/structure/parallel_structure.ts @@ -105,7 +105,7 @@ export class ParallelStructure extends Nub { case "Q": res = super.Calc(sVarCalc, rInit); if (res.ok) { - this.getParameter(sVarCalc).setValue(res.vCalc); + this.getParameter(sVarCalc).v = res.vCalc; } break; default: @@ -118,7 +118,7 @@ export class ParallelStructure extends Nub { // Suppression des extraResults : ils sont complétés plus bas pour chaque ouvrage res.resultElement.extraResults = {}; if (res.ok) { - this._children[structureIndex].getParameter(sVarCalc.symbol).setValue(res.vCalc); + this._children[structureIndex].getParameter(sVarCalc.symbol).v = res.vCalc; } } if (res.ok) { @@ -179,7 +179,7 @@ export class ParallelStructure extends Nub { */ protected CalcStructPrm(index: number, symbol: string, rInit?: number): Result { // Le débit restant sur la structure en calcul est : - this.structures[index].prms.Q.setValue(this.prms.Q.v - this.CalcQ(index).vCalc); + this.structures[index].prms.Q.v = this.prms.Q.v - this.CalcQ(index).vCalc; // Calcul du paramètre de la structure en calcul return this.structures[index].Calc(symbol, rInit); diff --git a/src/structure/structure.ts b/src/structure/structure.ts index 0d44f85b78c5971fd2856f550cc523eff6a063f1..2547d78fb204f3873e8b380469213b5d218e4ebf 100644 --- a/src/structure/structure.ts +++ b/src/structure/structure.ts @@ -180,14 +180,11 @@ export abstract class Structure extends Nub { ); } - // Mise à jour de h1 et h2 - this.prms.update_h1h2(); - // Gestion du débit nul const flagsNull = { ENUM_StructureFlowMode: StructureFlowMode.NULL, ENUM_StructureFlowRegime: StructureFlowRegime.NULL }; if (sVarCalc === "Q") { - if (this.prms.h1.v <= 0 || this.prms.Z1.v === this.prms.Z2.v || this.prms.W.v <= 0) { + if (this.prms.Z1.v <= this.prms.ZDV.v || this.prms.Z1.v === this.prms.Z2.v || this.prms.W.v <= 0) { return new Result(0, this, flagsNull); } } else if (this.prms.Q.v === 0) { @@ -229,20 +226,43 @@ export abstract class Structure extends Nub { } // Gestion de l'inversion de débit : on inverse l'amont et l'aval pour le calcul - if ((sVarCalc === "Q" && (this.prms.h1.v < this.prms.h2.v)) || (sVarCalc !== "Q" && this.prms.Q.v < 0)) { - [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion + if (sVarCalc !== "Q" && this.prms.Q.v < 0) { + [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion const res: Result = super.Calc(sVarCalc, rInit); + [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion + return res; + } + + // Calcul normal hors débit nul + return super.Calc(sVarCalc, rInit); + } + + /** + * Equation preprocessing + * @return true if inverted discharge + */ + public Equation(sVarCalc: string): Result { + Structure.CheckEquation(sVarCalc); + this.prms.update_h1h2(); + let res: Result; + if (this.prms.h1.v < this.prms.h2.v) { + [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion + res = this.CalcQ(); if (sVarCalc === "Q") { res.vCalc = -res.vCalc; } [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion - return res; + } else { + res = this.CalcQ(); } - - // Calcul normal hors débit nul et inversion de débit - return super.Calc(sVarCalc, rInit); + return res; } + /** + * Function to implement for the stage discharge equation of hydraulic structure + */ + protected abstract CalcQ(): Result; + protected getResultData() { return { ENUM_StructureFlowMode: this.getFlowMode(), diff --git a/src/structure/structure_cem88d.ts b/src/structure/structure_cem88d.ts index 8c08a710694713d4cc809de003996e08f22f269d..9b973e98dbac8f5021870bf97c4d82ff434a5086 100644 --- a/src/structure/structure_cem88d.ts +++ b/src/structure/structure_cem88d.ts @@ -6,8 +6,6 @@ import { LoiDebit } from "./structure_props"; export { RectangularStructureParams }; - - /** * Equation CEM88D : déversoir / orifice (pelle importante) Cemagref 1988 */ @@ -25,8 +23,7 @@ export class StructureWeirCem88d extends RectangularStructure { * Calcul analytique Q = f(Cd, L, h1, h2, W) CEM88D * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); let v: number; diff --git a/src/structure/structure_cem88v.ts b/src/structure/structure_cem88v.ts index f02f9f33d1ad74584231ff71ba53c300ea7dc7d0..e416201c256638bd992ac69dfd5b4c2d2acadcd7 100644 --- a/src/structure/structure_cem88v.ts +++ b/src/structure/structure_cem88v.ts @@ -20,8 +20,7 @@ export class StructureWeirCem88v extends RectangularStructure { * Calcul analytique Q = f(Cd, L, h1, h2, W) CEM88V * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); let v: number; diff --git a/src/structure/structure_cunge80.ts b/src/structure/structure_cunge80.ts index a6196e6217539d5320ae1b44749f17c2901abf48..2df43729d906b503cb579f1b9044231ecbbc1d82 100644 --- a/src/structure/structure_cunge80.ts +++ b/src/structure/structure_cunge80.ts @@ -25,8 +25,7 @@ export class StructureCunge80 extends RectangularStructure { * Calcul du débit avec l'équation Cunge80 * @param sVarCalc Variable à calculer (doit être égale à Q ici) */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); let v: number; diff --git a/src/structure/structure_kivi.ts b/src/structure/structure_kivi.ts index 7bbbaccbf369fd9a52b0ae52be69763a9595414f..55acfd95debee908badc0ee4cffaf2d45f03ac98 100644 --- a/src/structure/structure_kivi.ts +++ b/src/structure/structure_kivi.ts @@ -22,8 +22,7 @@ export class StructureKivi extends Structure { return this._prms as StructureKiviParams; } - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const res: Result = new Result(0, this, this.getResultData()); // p : pelle diff --git a/src/structure/structure_orifice_submerged.ts b/src/structure/structure_orifice_submerged.ts index ebbd4a20acaba8e0168f067c073159bbb0aa2db0..c353843274005201c90b71c9709f8adb6d712544 100644 --- a/src/structure/structure_orifice_submerged.ts +++ b/src/structure/structure_orifice_submerged.ts @@ -28,8 +28,7 @@ export class StructureOrificeSubmerged extends Structure { * Calcul du débit avec l'équation classique d'un orifice noyé * @param sVarCalc Variable à calculer (doit être égale à Q ici) */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); const v = this.prms.Cd.v * this.prms.S.v * Structure.R2G * Math.sqrt(this.prms.Z1.v - this.prms.Z2.v); diff --git a/src/structure/structure_rectangular_orifice_free.ts b/src/structure/structure_rectangular_orifice_free.ts index 22212ec0133b1bd02cf1e26b9174830e4dc21040..0b9b96e205e0fd9882f021e70bc57f09165d0cd8 100644 --- a/src/structure/structure_rectangular_orifice_free.ts +++ b/src/structure/structure_rectangular_orifice_free.ts @@ -21,8 +21,7 @@ export class StructureRectangularOrificeFree extends RectangularStructure { * Calcul du débit avec l'équation classique d'un orifice dénoyé * @param sVarCalc Variable à calculer (doit être égale à Q ici) */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v diff --git a/src/structure/structure_rectangular_orifice_submerged.ts b/src/structure/structure_rectangular_orifice_submerged.ts index 6c278cc6d14291cca136b721d08f2863f916c1c5..48e038bec84b771f139ac9f56bb8eea65c242942 100644 --- a/src/structure/structure_rectangular_orifice_submerged.ts +++ b/src/structure/structure_rectangular_orifice_submerged.ts @@ -24,8 +24,7 @@ export class StructureRectangularOrificeSubmerged extends RectangularStructure { * Calcul du débit avec l'équation classique d'un orifice noyé * @param sVarCalc Variable à calculer (doit être égale à Q ici) */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v diff --git a/src/structure/structure_triangular_trunc_weir.ts b/src/structure/structure_triangular_trunc_weir.ts index 4a709256902b2df80ba87018251b3fdf8b0ece24..dee0d35ff128dfeefd54b7f62339f8a9829ba1e8 100644 --- a/src/structure/structure_triangular_trunc_weir.ts +++ b/src/structure/structure_triangular_trunc_weir.ts @@ -28,8 +28,7 @@ export class StructureTriangularTruncWeirFree extends Structure { * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); let Q: number = this.prms.Cd.v * this.prms.BT.v / (this.prms.ZT.v - this.prms.ZDV.v); diff --git a/src/structure/structure_triangular_weir.ts b/src/structure/structure_triangular_weir.ts index ee505df9c103fe166a3f0cb955642393db99468b..e6def5d489e1ab88531e3187e89ef1ab6c628bfd 100644 --- a/src/structure/structure_triangular_weir.ts +++ b/src/structure/structure_triangular_weir.ts @@ -28,8 +28,7 @@ export class StructureTriangularWeir extends Structure { * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); let Q = this.prms.Cd.v * this.getTanFromDegrees(this.prms.alpha2.v) diff --git a/src/structure/structure_weir_free.ts b/src/structure/structure_weir_free.ts index 957791c6fe43bafc59d5d9616d6f53b67362d5b2..fcda6652dbe705186ab346058e190cb1be63893a 100644 --- a/src/structure/structure_weir_free.ts +++ b/src/structure/structure_weir_free.ts @@ -20,8 +20,7 @@ export class StructureWeirFree extends RectangularStructure { * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); const v = this.prms.Cd.v * this.prms.L.v * Structure.R2G * Math.pow(this.prms.h1.v, 1.5); diff --git a/src/structure/structure_weir_submerged_larinier.ts b/src/structure/structure_weir_submerged_larinier.ts index f7d7af00872ce3886c8e72ad4a2f8c1376007459..d34a1d337ada1894b9062c05e0b16997534c15ff 100644 --- a/src/structure/structure_weir_submerged_larinier.ts +++ b/src/structure/structure_weir_submerged_larinier.ts @@ -22,8 +22,7 @@ export class StructureWeirSubmergedLarinier extends RectangularStructure { * Calcul analytique Q = f(Cd, L, h1, h2, W) seuil dénoyé * @param sVarCalc Variable à calculer (doit être "Q") */ - public Equation(sVarCalc: string): Result { - Structure.CheckEquation(sVarCalc); + public CalcQ(): Result { const data = this.getResultData(); const v = this.prms.Cd.v * this.prms.L.v * Structure.R2G diff --git a/src/util/message.ts b/src/util/message.ts index cd5b6e391250a41ce7262a6cfe7b65f44dfc7648..8cdaa78ec234e7667ba8ce00801e1c5cf0541c54 100644 --- a/src/util/message.ts +++ b/src/util/message.ts @@ -43,6 +43,11 @@ export enum MessageCode { */ ERROR_DICHO_FUNCTION_VARIATION, + /** + * la cote amont Z1 est plus basse que la cote aval Z2 + */ + ERROR_ELEVATION_ZI_LOWER_THAN_Z2, + /** * les bornes de l'intervalle d'un ParamDomain sont incorrectes */ @@ -73,6 +78,11 @@ export enum MessageCode { */ ERROR_PARAMDEF_VALUE_FIXED, + /** + * la valeur d'un ParamDefinition doit être entière + */ + ERROR_PARAMDEF_VALUE_INTEGER, + /** * la valeur d'un ParamDefinition doit être > 0 */