diff --git a/spec/session/serialisation.spec.ts b/spec/session/serialisation.spec.ts index b3688fdc4c8fa943333837cc972b49b77f13b6dc..1a7331b7cda7af31072f1c84003c4563dc8eb3fb 100644 --- a/spec/session/serialisation.spec.ts +++ b/spec/session/serialisation.spec.ts @@ -206,7 +206,7 @@ describe("serialising / deserialising session - ", () => { it ("loaded serialized spaghetti session should have the right target for every link", () => { Session.getInstance().clear(); // tslint:disable-next-line:max-line-length - const session = `{"header":{"source":"jalhyd","format_version":"1.0","created":"2019-04-26T10:25:29.891Z"},"session":[{"uid":"ZHh1YW","props":{"calcType":2,"nodeType":2},"meta":{"title":"Sec. param."},"children":[{"uid":"bXB1Y3","props":{"calcType":14,"nodeType":2},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"SINGLE","value":1.2},{"symbol":"If","mode":"SINGLE","value":0.001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"LINK","targetNub":"YTBjcm","targetParam":"L"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001}]},{"uid":"eTgwMG","props":{"calcType":11,"nodeType":0},"meta":{"title":"Macro-rugo."},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"ZF1","mode":"LINK","targetNub":"dGx0em","targetParam":"Z1"},{"symbol":"L","mode":"SINGLE","value":6},{"symbol":"B","mode":"CALCUL"},{"symbol":"If","mode":"SINGLE","value":0.05},{"symbol":"Q","mode":"LINK","targetNub":"bXB1Y3","targetParam":"Q"},{"symbol":"Y","mode":"SINGLE","value":0.6},{"symbol":"Ks","mode":"SINGLE","value":0.01},{"symbol":"C","mode":"SINGLE","value":0.05},{"symbol":"PBD","mode":"SINGLE","value":0.5},{"symbol":"PBH","mode":"MINMAX","min":0.4,"max":1.6,"step":0.06000000000000001},{"symbol":"Cd0","mode":"SINGLE","value":1.5}]},{"uid":"dGx0em","props":{"calcType":8,"nodeType":0},"meta":{"title":"Ouvrages"},"children":[{"uid":"ZmZ3bX","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"CALCUL"},{"symbol":"Cd","mode":"SINGLE","value":0.6}]},{"uid":"aWo0M2","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"LINK","targetNub":"dGx0em","targetParam":"L"},{"symbol":"Cd","mode":"SINGLE","value":0.6}]},{"uid":"YTBjcm","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"LINK","targetNub":"aWo0M2","targetParam":"W"},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"Cd","mode":"LINK","targetNub":"ZmZ3bX","targetParam":"Cd"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"SINGLE","value":0.5},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"LINK","targetNub":"cXFraW","targetParam":"Z1"}]},{"uid":"dzA1OX","props":{"calcType":3,"nodeType":2},"meta":{"title":"R. uniforme"},"children":[{"uid":"Ynlna2","props":{"calcType":14,"nodeType":2},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"LINK","targetNub":"cXFraW","targetParam":"CvQT"},{"symbol":"If","mode":"MINMAX","min":0.0005,"max":0.002,"step":0.00007500000000000001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"CALCUL"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001}]},{"uid":"cXFraW","props":{"calcType":9,"nodeType":0},"meta":{"title":"Déver. dénoyés"},"children":[{"uid":"Zzd1cH","props":{"calcType":7,"nodeType":5,"structureType":0,"loiDebit":7},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"Cd","mode":"SINGLE","value":0.4}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"CALCUL"},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"BR","mode":"LINK","targetNub":"ZHh1YW","targetParam":"B"},{"symbol":"ZR","mode":"SINGLE","value":99}]}]}`; + const session = `{"header":{"source":"jalhyd","format_version":"1.0","created":"2019-04-26T10:25:29.891Z"},"session":[{"uid":"ZHh1YW","props":{"calcType":2,"nodeType":2},"meta":{"title":"Sec. param."},"children":[{"uid":"bXB1Y3","props":{"calcType":14,"nodeType":2},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"SINGLE","value":1.2},{"symbol":"If","mode":"SINGLE","value":0.001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"LINK","targetNub":"YTBjcm","targetParam":"L"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001}]},{"uid":"eTgwMG","props":{"calcType":11,"nodeType":0},"meta":{"title":"Macro-rugo."},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"ZF1","mode":"LINK","targetNub":"dGx0em","targetParam":"Z1"},{"symbol":"L","mode":"SINGLE","value":6},{"symbol":"B","mode":"CALCUL"},{"symbol":"If","mode":"SINGLE","value":0.05},{"symbol":"Q","mode":"LINK","targetNub":"bXB1Y3","targetParam":"Q"},{"symbol":"Y","mode":"SINGLE","value":0.6},{"symbol":"Ks","mode":"SINGLE","value":0.01},{"symbol":"C","mode":"SINGLE","value":0.05},{"symbol":"PBD","mode":"SINGLE","value":0.5},{"symbol":"PBH","mode":"MINMAX","min":0.4,"max":1.6,"step":0.06000000000000001},{"symbol":"Cd0","mode":"SINGLE","value":1.5}]},{"uid":"dGx0em","props":{"calcType":8,"nodeType":0},"meta":{"title":"Ouvrages"},"children":[{"uid":"ZmZ3bX","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"CALCUL"},{"symbol":"Cd","mode":"SINGLE","value":0.6}]},{"uid":"aWo0M2","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"SINGLE","value":0.5},{"symbol":"L","mode":"LINK","targetNub":"YTBjcm","targetParam":"L"},{"symbol":"Cd","mode":"SINGLE","value":0.6}]},{"uid":"YTBjcm","props":{"calcType":7,"nodeType":5,"structureType":1,"loiDebit":1},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"W","mode":"LINK","targetNub":"aWo0M2","targetParam":"W"},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"Cd","mode":"LINK","targetNub":"ZmZ3bX","targetParam":"Cd"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"SINGLE","value":0.5},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"Z2","mode":"LINK","targetNub":"cXFraW","targetParam":"Z1"}]},{"uid":"dzA1OX","props":{"calcType":3,"nodeType":2},"meta":{"title":"R. uniforme"},"children":[{"uid":"Ynlna2","props":{"calcType":14,"nodeType":2},"children":[],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Ks","mode":"SINGLE","value":40},{"symbol":"Q","mode":"LINK","targetNub":"cXFraW","targetParam":"CvQT"},{"symbol":"If","mode":"MINMAX","min":0.0005,"max":0.002,"step":0.00007500000000000001},{"symbol":"YB","mode":"SINGLE","value":1},{"symbol":"Y","mode":"SINGLE","value":0.8},{"symbol":"LargeurBerge","mode":"CALCUL"}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001}]},{"uid":"cXFraW","props":{"calcType":9,"nodeType":0},"meta":{"title":"Déver. dénoyés"},"children":[{"uid":"Zzd1cH","props":{"calcType":7,"nodeType":5,"structureType":0,"loiDebit":7},"children":[],"parameters":[{"symbol":"ZDV","mode":"SINGLE","value":100},{"symbol":"L","mode":"SINGLE","value":2},{"symbol":"Cd","mode":"SINGLE","value":0.4}]}],"parameters":[{"symbol":"Pr","mode":"SINGLE","value":0.0001},{"symbol":"Q","mode":"CALCUL"},{"symbol":"Z1","mode":"SINGLE","value":102},{"symbol":"BR","mode":"LINK","targetNub":"ZHh1YW","targetParam":"B"},{"symbol":"ZR","mode":"SINGLE","value":99}]}]}`; Session.getInstance().unserialise(session); expect(Session.getInstance().getNumberOfNubs()).toBe(5); @@ -230,7 +230,7 @@ describe("serialising / deserialising session - ", () => { expect(OU).toBeDefined(); checkLink(OU.prms.Z2, DD, "Z1"); const struct2 = (OU.structures[1] as RectangularStructure); - checkLink(struct2.prms.L, OU, "L"); // @TODO devrait être interdit ! :/ + checkLink(struct2.prms.L, OU.structures[2], "L"); const struct3 = (OU.structures[2] as RectangularStructure); checkLink(struct3.prms.W, OU.structures[1], "W"); checkLink(struct3.prms.Cd, OU.structures[0], "Cd"); diff --git a/spec/value_ref/value_ref.spec.ts b/spec/value_ref/value_ref.spec.ts index c101298864c894401e8b4b5257bdcbbba19af3a5..937377c6cee52c54652dd4f673e7b7bbc92a5548 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, ParamValueMode } from "../../src/index"; +import { Result, Session } from "../../src/index"; import { NubTest, NubTestParams } from "../nubtest"; import { precDigits } from "../test_config"; diff --git a/spec/value_ref/value_ref_chained_computation.spec.ts b/spec/value_ref/value_ref_chained_computation.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..29a796a4bb01b7a17b3287bf2d488256ec6eabf2 --- /dev/null +++ b/spec/value_ref/value_ref_chained_computation.spec.ts @@ -0,0 +1,98 @@ +import { Cloisons, CloisonsParams, CreateStructure, cSnRectang, LoiDebit, + ParamsSectionRectang, SectionParametree, Session } from "../../src/index"; +import { PabDimension, PabDimensionParams } from "../../src/pab/pab_dimension"; +import { PabPuissance, PabPuissanceParams } from "../../src/pab/pab_puissance"; +import { RegimeUniforme } from "../../src/regime_uniforme"; + +describe("chained computation of linked Nubs : ", () => { + + it("links through results should be computed in chain but links through parameters should not", () => { + // PAB: Dimensions + const prmsDim = new PabDimensionParams( + 4, // Longueur L + 1, // Largeur W + 0.5, // Tirant d'eau Y + 2 // Volume V + ); + const dim = new PabDimension(prmsDim); + dim.calculatedParam = prmsDim.Y; + + // PAB: Puissance + const prmsPui = new PabPuissanceParams( + 0.3, // Chute entre bassins DH (m) + 0.1, // Débit Q (m3/s) + 0.5, // Volume V (m3) + 588.6 // Puissance dissipée PV (W/m3) + ); + const pui = new PabPuissance(prmsPui); + pui.calculatedParam = prmsPui.V; + + // PAB: Cloisons + const prmsClo = new CloisonsParams(1.5, 102, 10, 1, 1, 0.5); + const clo = new Cloisons(prmsClo); + clo.addChild(CreateStructure(LoiDebit.OrificeSubmerged, clo)); + clo.calculatedParam = prmsClo.Q; + + Session.getInstance().clear(); + Session.getInstance().registerNub(dim); + Session.getInstance().registerNub(pui); + Session.getInstance().registerNub(clo); + + prmsClo.LB.defineReference(dim, "L"); + prmsClo.BB.defineReference(dim, "W"); + prmsClo.DH.defineReference(pui, "DH"); + prmsDim.V.defineReference(pui, "V"); + + clo.CalcSerie(); + expect(dim.result).toBeUndefined(); + expect(pui.result).toBeUndefined(); + + dim.CalcSerie(); + expect(pui.result).toBeDefined(); + }); + + it("2 Nubs linked to each other through 1 result and 1 parameter should not lead to infinite recursion", () => { + // Section Parametree + const paramSp = new ParamsSectionRectang( + undefined, // tirant d'eau + 2.5, // largeur de fond + 40, // Ks=Strickler + 2, // Q=Débit + 0.001, // If=pente du fond + 1 // YB=hauteur de berge + ); + const sectSp = new cSnRectang(paramSp); + const sp = new SectionParametree(sectSp); + + // Regime Uniforme + const paramRu = new ParamsSectionRectang( + undefined, // tirant d'eau + 2.5, // largeur de fond + 40, // Ks=Strickler + 2, // Q=Débit + 0.001, // If=pente du fond + 1 // YB=hauteur de berge + ); + const sectRu = new cSnRectang(paramRu); + const ru = new RegimeUniforme(sectRu); + + Session.getInstance().clear(); + Session.getInstance().registerNub(sp); + Session.getInstance().registerNub(ru); + + paramRu.LargeurBerge.defineReference(sp, "B"); + paramSp.If.defineReference(sectRu, "If"); + + try { + ru.CalcSerie(); // should not fail + } catch (e) { + fail(); + } + + try { + sp.CalcSerie(); // should not fail + } catch (e) { + fail(); + } + }); +}); diff --git a/spec/value_ref/value_ref_circularity.spec.ts b/spec/value_ref/value_ref_circularity.spec.ts index 7c70361415e00f4a9e0333cbf522acd3cec7bb46..64535f7629de2cce47754825b1511d54727d67b0 100644 --- a/spec/value_ref/value_ref_circularity.spec.ts +++ b/spec/value_ref/value_ref_circularity.spec.ts @@ -1,4 +1,6 @@ -import { Session } from "../../src/index"; +import { CreateStructure, LoiDebit, ParallelStructure, + ParallelStructureParams, Session, Structure } from "../../src/index"; +import { RectangularStructureParams } from "../../src/structure/structure_cem88d"; import { NubTest, NubTestParams } from "../nubtest"; /** @@ -100,5 +102,37 @@ describe("référence d'un paramètre à un autre : ", () => { // tslint:disable-next-line:no-empty } catch (e) { } }); + + it("test 5 : ouvrages en parallèle", () => { + // cas de figure : + // - le param. de l'ouvrage 2 référence le param. de l'ouvrage 1 (ne doit pas échouer) + // - le param. de l'ouvrage 2 référence le param. en calcul de l'ouvrage 1, + // via le résultat du Nub ParallelStructure (doit échouer) + + const psp: ParallelStructureParams = new ParallelStructureParams(1, 2, 3); + const pst = new ParallelStructure(psp); + const st1: Structure = CreateStructure(LoiDebit.WeirCem88d, pst); + pst.addChild(st1); + const prmS1 = (st1.prms as RectangularStructureParams); + const st2: Structure = CreateStructure(LoiDebit.WeirCem88d, pst); + const prmS2 = (st2.prms as RectangularStructureParams); + pst.addChild(st2); + pst.calculatedParam = prmS1.L; + + Session.getInstance().clear(); + Session.getInstance().registerNub(pst); + + try { + prmS2.W.defineReference(st1, "W"); // ne doit pas échouer + } catch (e) { + fail(); + } + + try { + prmS2.L.defineReference(pst, "L"); // doit échouer + fail(); + // tslint:disable-next-line:no-empty + } catch (e) { } + }); }); }); diff --git a/src/nub.ts b/src/nub.ts index e5cb9379d75054b1b2bdd0bb4da1ee4324903294..721f0f85394cd42cfeb562009ba52ccbd0295a7b 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -475,11 +475,12 @@ export abstract class Nub extends ComputeNode implements IObservable { if (p.isLinkableTo(src)) { // if p is a CALC param of a Structure other than "Q" // (structures always have Q as CALC param and cannot have another) - // or a CALC param of a Section, + // or a CALC param of a Section, that is not sibling of the target + // (to prevent circular dependencies among ParallelStructures), // expose its parent if ( ( - (this instanceof Structure && p.symbol !== "Q") + (this instanceof Structure && p.symbol !== "Q" && ! this.isSiblingOf(src.nubUid)) || this instanceof acSection ) && (p.valueMode === ParamValueMode.CALCUL) @@ -545,13 +546,34 @@ export abstract class Nub extends ComputeNode implements IObservable { return false; } + /** + * Returns true if the given Nub UID : + * - is the current Nub UID + * - is the UID of any of the current Nub's siblings (children of the same parent) + */ + public isSiblingOf(uid: string): boolean { + if (this.uid === uid) { + return true; + } + const parent = this.getParent(); + if (parent) { + for (const c of parent.getChildren()) { + if (c.uid === uid) { + return true; + } + } + return true; + } + return false; + } + /** * Returns all Nubs whose results are required by the given one, * without following links (stops when it finds a Nub that has to * be calculated). Used to trigger chain calculation. */ public getRequiredNubs(visited: string[] = []) { - let requiredNubs: Nub[] = []; + const requiredNubs: Nub[] = []; // prevent loops if (! visited.includes(this.uid)) { visited.push(this.uid); @@ -564,10 +586,6 @@ export abstract class Nub extends ComputeNode implements IObservable { // a Nub is required if I depend on its result if (this.dependsOnNubResult(nub, false)) { requiredNubs.push(nub); - } else { - // check if linked Nub needs the result of another one, in - // which case the latter's calculation is needed too - requiredNubs = requiredNubs.concat(nub.getRequiredNubs(visited)); } } }