diff --git a/spec/param/param_modes.spec.ts b/spec/param/param_modes.spec.ts index b01100c4958989eab2f3aa0e6c5e052771d29d89..bf3ecb6b04a4ce0570b2fd79ded09d3c7684147a 100644 --- a/spec/param/param_modes.spec.ts +++ b/spec/param/param_modes.spec.ts @@ -141,17 +141,12 @@ function createEnv() { function checkConsistency(nubToCheck: Nub) { expect(nubToCheck.calculatedParam).toBeDefined(); let calcCount = 0; - let varCount = 0; for (const p of nubToCheck.parameterIterator) { if (p.valueMode === ParamValueMode.CALCUL) { calcCount++; } - if (p.valueMode === ParamValueMode.MINMAX || p.valueMode === ParamValueMode.LISTE) { - varCount++; - } } expect(calcCount).toBe(1); - expect(varCount).toBeLessThanOrEqual(1); nubToCheck.CalcSerie(); expect(nubToCheck.result).toBeDefined(); @@ -232,8 +227,7 @@ describe("cohérence des modes de paramètres : ", () => { testModesPermutations(nub2); }); - // @TODO reenable after fixing jalhyd#74 - xit("ouvrages en parallèle : Cloisons", () => { + it("ouvrages en parallèle : Cloisons", () => { createEnv(); testModesPermutations(nub3); }); diff --git a/spec/param/param_multivar.spec.ts b/spec/param/param_multivar.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..dea5b5bb4695c30cba15526aa5defbf588d092f9 --- /dev/null +++ b/spec/param/param_multivar.spec.ts @@ -0,0 +1,441 @@ +import { CreateStructure, ExtensionStrategy, LoiDebit, ParallelStructure, ParallelStructureParams, + ParamValueMode, Structure, Session} from "../../src/index"; +import { RectangularStructureParams } from "../../src/structure/structure_cem88d"; + +let prms1: ParallelStructureParams; +let nub1: ParallelStructure; +let struct1: Structure; +let prmsStruct1: RectangularStructureParams; + +let prms2: ParallelStructureParams; +let nub2: ParallelStructure; +let struct2: Structure; +let prmsStruct2: RectangularStructureParams; + +function createSingleNubEnv() { + prms1 = new ParallelStructureParams(0.5, 102, 101.5); + nub1 = new ParallelStructure(prms1); + struct1 = CreateStructure(LoiDebit.Cunge80, nub1); + prmsStruct1 = struct1.prms as RectangularStructureParams; + nub1.addChild(struct1); +} + +function createLinkedNubEnv() { + prms1 = new ParallelStructureParams(0.5, 102, 101.5); + nub1 = new ParallelStructure(prms1); + struct1 = CreateStructure(LoiDebit.Cunge80, nub1); + prmsStruct1 = struct1.prms as RectangularStructureParams; + nub1.addChild(struct1); + + prms2 = new ParallelStructureParams(0.5, 102, 101.5); + nub2 = new ParallelStructure(prms2); + struct2 = CreateStructure(LoiDebit.Cunge80, nub2); + prmsStruct2 = struct2.prms as RectangularStructureParams; + nub2.addChild(struct2); + + Session.getInstance().clear(); + Session.getInstance().registerNub(nub1); + Session.getInstance().registerNub(nub2); + + prms2.Z1.defineReference(nub1, "Z1"); + prmsStruct2.L.defineReference(struct1, "L"); +} + +/** + * Generates a random-length list of numbers close + * @param refVal reference value + * @param minSize minimum size of the list to be returned + * @param maxSize maximum size of the list to be returned + * @param maxDev maximum deviation, so that generated numbers + * value v verifies (refVal - maxDev) < v < (refVal + maxDev) + * @param sort if true, list will be ordered + */ +function randomList( + refVal: number, minSize: number = 2, maxSize: number = 20, maxDev: number = 3, sort: boolean = true +): number[] { + let list: number[] = []; + const size = minSize + Math.floor(Math.random() * ((maxSize - minSize) + 1)); // between minSize and maxSize + for (let i = 0; i < size; i++) { + let dev = (Math.random() * (2 * maxDev)) - (maxDev + 1); // between -maxDev and maxDev + dev = Number(Math.round(Number(dev + "e3")) + "e-3"); // trick to properly round to 3 decimals + list.push(refVal + dev); + } + if (sort) { + list = list.sort((a, b) => a - b); + } + return list; +} + +describe("multiple variated parameters - ", () => { + + describe("on the same Nub, with REPEAT_LAST strategy - ", () => { + + it("test 1 : minmax < list", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 2 : minmax < minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues(1.89, 2.1, 0.03); // 8 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(8); + }); + + it("test 3 : list < minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.1); // 21 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(21); + }); + + it("test 4 : list < list", () => { + createSingleNubEnv(); + prms1.Z1.setValues([ 100, 101, 102 ]); // 3 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 5 : list = list", () => { + createSingleNubEnv(); + prms1.Z1.setValues([ 100, 100.3, 100.7, 101, 101.3, 101.7, 102, 102.3, 115 ]); // 9 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 6 : list = minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues(1.89, 2.15, 0.06); // 5 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(5); + }); + + it("test 7 : all parameters varying with random lengths", () => { + createSingleNubEnv(); + let longest = 0; + let sparedParam = null; + // set all parameters to LIST mode with random length (except the first that has to stay in CALC mode) + for (const p of nub1.parameterIterator) { + if (p.visible) { + if (! sparedParam) { + sparedParam = p; + nub1.calculatedParam = p; + } else { + const rl = randomList(p.singleValue); + longest = Math.max(longest, rl.length); + p.setValues(rl); + p.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + } + } + } + // check that all parameters are varying + for (const p of nub1.parameterIterator) { + if (p.visible && p !== sparedParam) { + expect(p.hasMultipleValues).toBe(true); + } + } + // check that calculation works and length of result is length of the longest values list + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(longest); + }); + }); + + describe("on the same Nub, with RECYCLE strategy - ", () => { + + it("test 1 : minmax < list", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 2 : minmax < minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues(1.89, 2.1, 0.03); // 8 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(8); + }); + + it("test 3 : list < minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.1); // 21 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(21); + }); + + it("test 4 : list < list", () => { + createSingleNubEnv(); + prms1.Z1.setValues([ 100, 101, 102 ]); // 3 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 5 : list = list", () => { + createSingleNubEnv(); + prms1.Z1.setValues([ 100, 100.3, 100.7, 101, 101.3, 101.7, 102, 102.3, 115 ]); // 9 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 6 : list = minmax", () => { + createSingleNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.RECYCLE; + prmsStruct1.L.setValues(1.89, 2.15, 0.06); // 5 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.RECYCLE; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(5); + }); + + it("test 7 : all parameters varying with random lengths", () => { + createSingleNubEnv(); + let longest = 0; + let sparedParam = null; + // set all parameters to LIST mode with random length (except the first that has to stay in CALC mode) + for (const p of nub1.parameterIterator) { + if (p.visible) { + if (! sparedParam) { + sparedParam = p; + nub1.calculatedParam = p; + } else { + const rl = randomList(p.singleValue); + longest = Math.max(longest, rl.length); + p.setValues(rl); + p.extensionStrategy = ExtensionStrategy.RECYCLE; + } + } + } + // check that all parameters are varying + for (const p of nub1.parameterIterator) { + if (p.visible && p !== sparedParam) { + expect(p.hasMultipleValues).toBe(true); + } + } + // check that calculation works and length of result is length of the longest values list + const res = nub1.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(longest); + }); + }); + + describe("on different linked Nubs, with REPEAT_LAST strategy - ", () => { + + it("test 1 : minmax < list", () => { + createLinkedNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 2 : minmax < minmax", () => { + createLinkedNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues(1.89, 2.1, 0.03); // 8 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(8); + }); + + it("test 3 : list < minmax", () => { + createLinkedNubEnv(); + prms1.Z1.setValues(100, 102, 0.1); // 21 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(21); + }); + + it("test 4 : list < list", () => { + createLinkedNubEnv(); + prms1.Z1.setValues([ 100, 101, 102 ]); // 3 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 5 : list = list", () => { + createLinkedNubEnv(); + prms1.Z1.setValues([ 100, 100.3, 100.7, 101, 101.3, 101.7, 102, 102.3, 115 ]); // 9 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues([ 1.89, 1.91, 1.99, 2, 1.7, 2.1, 2.18, 2.23, 2.6 ]); // 9 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.LISTE); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.LISTE); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(9); + }); + + it("test 6 : list = minmax", () => { + createLinkedNubEnv(); + prms1.Z1.setValues(100, 102, 0.5); // 5 values + prms1.Z1.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + prmsStruct1.L.setValues(1.89, 2.15, 0.06); // 5 values + prmsStruct1.L.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + // check that both parameters are varying + expect(prms1.Z1.valueMode).toBe(ParamValueMode.MINMAX); + expect(prmsStruct1.L.valueMode).toBe(ParamValueMode.MINMAX); + // check that calculation works + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(5); + }); + + it("test 7 : all parameters varying with random lengths", () => { + createLinkedNubEnv(); + let longest = 0; + let sparedParam = null; + // set all parameters to LIST mode with random length (except the first that has to stay in CALC mode) + for (const p of nub2.parameterIterator) { + if (p.visible) { + if (! sparedParam) { + sparedParam = p; + nub2.calculatedParam = p; + } else { + if (p.valueMode !== ParamValueMode.LINK) { + const rl = randomList(p.singleValue); + longest = Math.max(longest, rl.length); + p.setValues(rl); + p.extensionStrategy = ExtensionStrategy.REPEAT_LAST; + } + } + } + } + // check that all parameters are varying + for (const p of nub2.parameterIterator) { + if (p.visible && p !== sparedParam && p.valueMode !== ParamValueMode.LINK) { + expect(p.hasMultipleValues).toBe(true); + } + } + // check that calculation works and length of result is length of the longest values list + const res = nub2.CalcSerie(); + expect(res).toBeDefined(); + expect(res.resultElements.length).toBe(longest); + }); + }); +}); diff --git a/spec/value_ref/value_ref.spec.ts b/spec/value_ref/value_ref.spec.ts index 937377c6cee52c54652dd4f673e7b7bbc92a5548..d6fbf2a8b0fba94df292cd1896aca35d41e3f200 100644 --- a/spec/value_ref/value_ref.spec.ts +++ b/spec/value_ref/value_ref.spec.ts @@ -245,5 +245,27 @@ describe("référence d'un paramètre à un autre : ", () => { } expect(n).toEqual(input.length); }); + + it("test 5", () => { + // cas de figure : + // nub2.A est lié à nub1.A (valeur variée) + // lecture de nub2.A + + createEnv(); + + const input = [2, 3, 4, 5, 6]; + 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.singleValue = 0; + prm2.A.defineReference(nub1, "A"); + + let ndx = 0; + for (const v of prm2.A.paramValues.getValuesIterator()) { + expect(v).toEqual(input[ndx]); + ndx++; + } + expect(ndx).toEqual(input.length); + }); }); }); diff --git a/src/nub.ts b/src/nub.ts index b0877e6d0db88451380058c86861dcb55a78bf76..43970a54e102804ab30088d383b8e0af628c7806 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -146,8 +146,25 @@ export abstract class Nub extends ComputeNode implements IObservable { } /** - * Resets the calculated parameter to the default one if it is in SINGLE - * mode, or else to the first calculable parameter other than requirer. + * Finds the previous calculated parameter and sets its mode to SINGLE + */ + public unsetCalculatedParam(except: ParamDefinition) { + for (const p of this.parameterIterator) { + if ( + p.valueMode === ParamValueMode.CALCUL + && p !== except + ) { + p.setValueMode(ParamValueMode.SINGLE, false); + } + } + } + + /** + * Tries to reset the calculated parameter, successively, to : + * - the default one if it is in SINGLE mode + * - the first SINGLE calculable parameter other than requirer + * - the first MINMAX/LISTE calculable parameter other than requirer + * * If no default calculated parameter is defined, does nothing. */ public resetDefaultCalculatedParam(requirer?: ParamDefinition) { @@ -155,15 +172,20 @@ export abstract class Nub extends ComputeNode implements IObservable { // if default calculated param is not eligible to CALC mode if ( requirer === this._defaultCalculatedParam - || this._defaultCalculatedParam.valueMode !== ParamValueMode.SINGLE + || ! [ + ParamValueMode.SINGLE, + ParamValueMode.MINMAX, + ParamValueMode.LISTE + ].includes(this._defaultCalculatedParam.valueMode + ) ) { // first SINGLE calculable parameter if any - const newCalculatedParam = this.findFirstSingleParameter(requirer); + const newCalculatedParam = this.findFirstCalculableParameter(requirer); if (newCalculatedParam) { this.calculatedParam = newCalculatedParam; } else { // @TODO throws when a new linkable nub is added, and all parameters are already linked ! - throw Error("resetDefaultCalculatedParam : could not find any SINGLE parameter"); + throw Error("resetDefaultCalculatedParam : could not find any SINGLE/MINMAX/LISTE parameter"); } } else { // default one @@ -176,17 +198,17 @@ export abstract class Nub extends ComputeNode implements IObservable { /** * Returns the first visible calculable parameter other than "Pr", - * and other than otherThan, that is set to SINGLE mode - * (there might be none) + * and other than otherThan, that is set to SINGLE, MINMAX or LISTE + * mode (there might be none) */ - public findFirstSingleParameter(otherThan?: ParamDefinition) { + public findFirstCalculableParameter(otherThan?: ParamDefinition) { for (const p of this.parameterIterator) { if ( [ ParamCalculability.EQUATION, ParamCalculability.DICHO ].includes(p.calculability) && p.symbol !== "Pr" && p.visible && p !== otherThan - && p.valueMode === ParamValueMode.SINGLE + && [ ParamValueMode.SINGLE, ParamValueMode.MINMAX, ParamValueMode.LISTE ].includes(p.valueMode) ) { return p; } @@ -194,45 +216,6 @@ export abstract class Nub extends ComputeNode implements IObservable { return undefined; } - /** - * Resets all parameters to SINGLE mode, except sourceParam (the one that asked - * for the change) and parameters in LINK mode. - * If exceptMode is defined, parameters in this mode won't be affected either. - * - * Used to ensure that - * - exactly one parameter is in CALCUL mode - * - at most one parameter variates (MIMAX / LISTE mode) - */ - public ensureParametersConsistency(sourceParam: ParamDefinition, exceptMode: ParamValueMode|ParamValueMode[] = []) { - if (! Array.isArray(exceptMode)) { - exceptMode = [ exceptMode ]; - } - // console.log(`nub ${this.uid} (${this.constructor.name})`); - // console.log(`(calculated parameter: ${this.calculatedParam.symbol})`); - for (const p of this.parameterIterator) { - if ( - p !== sourceParam - && ! exceptMode.includes(p.valueMode) - && ( - // don't touch linked parameters - p.valueMode !== ParamValueMode.LINK - || ( // unless they are linked to multiple values… - p.isReferenceDefined() - && p.hasMultipleValues - // …and we're not skipping multiple values - && ! exceptMode.includes(ParamValueMode.MINMAX) - && ! exceptMode.includes(ParamValueMode.LISTE) - ) - ) - && p.valueMode !== ParamValueMode.SINGLE - ) { - // console.log(">> resetting", p.symbol); - // "false" prevents infinite loop when managing CALC params - p.setValueMode(ParamValueMode.SINGLE, false); - } - } - } - /** * Formule utilisée pour le calcul analytique (solution directe ou méthode de résolution spécifique) */ @@ -304,81 +287,81 @@ export abstract class Nub extends ComputeNode implements IObservable { * @param sDonnee éventuel symbole / paire symbole-uid du paramètre à calculer */ public CalcSerie(rInit?: number, sDonnee?: any): Result { - // instance de ParamValues utilisée pour le paramètre varié (qui peut être un paramètre référencé (importé)) - let variatedParam: ParamDefinition; - let variatedValues: ParamValues; + // variated parameters caracteristics + const variated: Array<{ param: ParamDefinition, values: ParamValues }> = []; + // prepare calculation this.progress = 0; this.triggerChainCalculation(); - this.copySingleValuesToSandboxValues(); // check which values are variating, if any for (const p of this.parameterIterator) { - switch (p.valueMode) { - case ParamValueMode.SINGLE: - case ParamValueMode.CALCUL: - break; - - case ParamValueMode.LISTE: - case ParamValueMode.MINMAX: - variatedParam = this.setVariatedValues(p, variatedParam); - break; - - case ParamValueMode.LINK: - if ( - p.isReferenceDefined() - && p.referencedValue.hasMultipleValues() - ) { - variatedParam = this.setVariatedValues(p, variatedParam); - } - break; - - default: - // tslint:disable-next-line:max-line-length - throw new Error(`CalcSerie() : valeur de ParamValueMode ${ParamValueMode[p.valueMode]} non prise en charge`); + if ( + p.valueMode === ParamValueMode.LISTE + || p.valueMode === ParamValueMode.MINMAX + || ( + p.valueMode === ParamValueMode.LINK + && p.isReferenceDefined() + && p.referencedValue.hasMultipleValues() + ) + ) { + variated.push({ + param: p, + // extract variated values from variated Parameters + // (in LINK mode, proxies to target data) + values: p.paramValues + }); } } - let computedSymbol: any; - if (sDonnee) { - computedSymbol = sDonnee; - } else { - if (this.calculatedParam === undefined) { - throw new Error(`CalcSerie() : aucun paramètre à calculer`); - } - computedSymbol = this.calculatedParamDescriptor; - } + // find calculated parameter + const computedSymbol = this.findCalculatedParameter(sDonnee); - if (rInit === undefined) { + if (rInit === undefined && this.calculatedParam) { rInit = this.calculatedParam.v; } - if (variatedParam === undefined) { - this._result = this.Calc(computedSymbol, rInit); // résultat dans this._result - // update progress to 100% + if (variated.length === 0) { // no parameter is varying + this._result = this.doCalc(computedSymbol, rInit); this.progress = 100; - } else { - // extract variated values from variated Parameter - // (in LINK mode, proxies to target data) - variatedValues = variatedParam.paramValues; + } else { // at least one parameter is varying + // find longest series + let longest = 0; + for (let i = 0; i < variated.length; i++) { + if (variated[i].values.valuesIterator.count() > variated[longest].values.valuesIterator.count()) { + longest = i; + } + } + const size = variated[longest].values.valuesIterator.count(); // grant the remaining percentage of the progressbar to local calculation // (should be 50% if any chain calculation occurred, 100% otherwise) let progressStep; const remainingProgress = 100 - this.progress; - const nbValues = variatedValues.valuesIterator.count(); - progressStep = remainingProgress / nbValues; + progressStep = remainingProgress / size; const res = new Result(undefined, this); - variatedValues.initValuesIterator(false); - while (variatedValues.hasNext) { - const currentIteratorValue = variatedValues.next(); - variatedParam.v = currentIteratorValue.value; // copy to local sandbox value + // (re)init all iterators + for (const v of variated) { + if (v === variated[longest]) { + v.values.initValuesIterator(false); + } else { + v.values.initValuesIterator(false, size); + } + } - this.Calc(computedSymbol, rInit); // résultat dans this._result + // iterate over longest series (in fact any series would do) + while (variated[longest].values.hasNext) { + // get next value for all variating parameters + for (const v of variated) { + const currentIteratorValue = v.values.next(); + v.param.v = currentIteratorValue.value; + } + // calculate + this.doCalc(computedSymbol, rInit); // résultat dans this._result if (this._result.ok) { res.addResultElement(this._result.resultElement); res.addLog(this._result.log); @@ -393,8 +376,10 @@ export abstract class Nub extends ComputeNode implements IObservable { this.progress = 100; } - const realSymbol = (typeof computedSymbol === "string") ? computedSymbol : computedSymbol.symbol; - this._result.name = realSymbol; + if (computedSymbol !== undefined) { + const realSymbol = (typeof computedSymbol === "string") ? computedSymbol : computedSymbol.symbol; + this._result.name = realSymbol; + } this.notifyResultUpdated(); @@ -1098,6 +1083,23 @@ export abstract class Nub extends ComputeNode implements IObservable { this._observable.notifyObservers(data, sender); } + protected findCalculatedParameter(sDonnee: any): any { + let computedSymbol: any; + if (sDonnee) { + computedSymbol = sDonnee; + } else { + if (this.calculatedParam === undefined) { + throw new Error(`CalcSerie() : aucun paramètre à calculer`); + } + computedSymbol = this.calculatedParamDescriptor; + } + return computedSymbol; + } + + protected doCalc(computedSymbol?: any, rInit?: number) { + return this.Calc(computedSymbol, rInit); + } + /** * Returns values of parameters and the result of the calculation for the calculated parameter * @param sVarCalc Symbol of the calculated param @@ -1147,18 +1149,6 @@ export abstract class Nub extends ComputeNode implements IObservable { return Nub.prototype.Calc.call(this, sVarCalc, rInit); } - /** - * Sets the variated values and warns if there were already some - */ - protected setVariatedValues(newValues: ParamDefinition, oldValues: ParamDefinition): ParamDefinition { - if (oldValues === undefined) { - return newValues; - } else { - // tslint:disable-next-line:max-line-length - throw new Error(`CalcSerie() : Paramètres à varier redondant : ${newValues.name}`); - } - } - /** * Used by GUI to update results display */ diff --git a/src/param/param-definition.ts b/src/param/param-definition.ts index 263440ea7055b9fdf6fa0b76684abee7279a3def..07d16ed6fd6c7cbd09b76acd734271d529fc94e7 100644 --- a/src/param/param-definition.ts +++ b/src/param/param-definition.ts @@ -43,6 +43,19 @@ export enum ParamFamily { // SPEEDS // vitesses, seulement des résultats } +/** + * Strategy to apply when multiple parameters are variating, and + * values series have to be extended for sizes to match + */ +export enum ExtensionStrategy { + REPEAT_LAST, // repeat last value as many times as needed + RECYCLE // repeat the whole series from the beginning + // autres propositions : + // PAD_LEFT // pad with zeroes at the beginning ? + // PAD_RIGHT // pad with zeroes at the end ? + // INTERPOLATE // insert regular steps between first and last value +} + /** * Paramètre avec symbole, famille, domaine de définition, calculabilité, * pointant éventuellement vers un autre paramètre / résultat @@ -55,6 +68,9 @@ export class ParamDefinition implements INamedIterableValues, IObservable { /** sandbox value used during calculation */ public v: number; + /** extension strategy, when multiple parameters vary */ + private _extensionStrategy: ExtensionStrategy; + /** mode de génération des valeurs : min/max, liste, ... */ private _valueMode: ParamValueMode; @@ -90,7 +106,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable { this._observable = new Observable(); this._paramValues = new ParamValues(); - // set single value and copy it to currentValue + // set single value and copy it to sandbox value this._paramValues.singleValue = val; this.v = val; @@ -98,6 +114,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable { this._family = family; this.visible = visible; this.valueMode = ParamValueMode.SINGLE; + this.extensionStrategy = ExtensionStrategy.REPEAT_LAST; if (d instanceof ParamDomain) { this._domain = d; @@ -189,6 +206,20 @@ export class ParamDefinition implements INamedIterableValues, IObservable { return this._domain.interval; } + public get extensionStrategy(): ExtensionStrategy { + return this._extensionStrategy; + } + + public set extensionStrategy(strategy: ExtensionStrategy) { + this._extensionStrategy = strategy; + // synchronise with underlying local ParamValues (for iterator), except for links + if ([ ParamValueMode.SINGLE, ParamValueMode.MINMAX, ParamValueMode.LISTE ].includes(this.valueMode)) { + if (this._paramValues) { + this._paramValues.extensionStrategy = strategy; + } + } + } + public get valueMode(): ParamValueMode { return this._valueMode; } @@ -203,8 +234,8 @@ export class ParamDefinition implements INamedIterableValues, IObservable { } /** - * Sets the value mode and asks the Nub to ensure all parameters requirements are met - * @see Nub::ensureParametersConsistency() + * Sets the value mode and asks the Nub to ensure there is only one parameter + * in CALC mode * * If propagateToCalculatedParam is true, any param that goes from CALC mode * to any other mode will trigger a reset of the default calculated param at @@ -221,88 +252,19 @@ export class ParamDefinition implements INamedIterableValues, IObservable { return; } - switch (oldMode) { - case ParamValueMode.SINGLE: // ancien état - switch (newMode) { - case ParamValueMode.MINMAX: // nouvel état - case ParamValueMode.LISTE: - this.ensureParametersConsistency(this, ParamValueMode.CALCUL); - break; - - case ParamValueMode.CALCUL: // nouvel état - this.ensureParametersConsistency(this, [ ParamValueMode.MINMAX, ParamValueMode.LISTE ]); - break; - - case ParamValueMode.LINK: // nouvel état - if ( - this.isReferenceDefined() - && this.hasMultipleValues - ) { - this.ensureParametersConsistency(this); // reset existing variable param - } - break; - } - break; - - case ParamValueMode.LISTE: // ancien état - case ParamValueMode.MINMAX: - switch (newMode) { - case ParamValueMode.CALCUL: // nouvel état - this.ensureParametersConsistency(this); - break; - - case ParamValueMode.LINK: // nouvel état - if ( - this.isReferenceDefined() - && this.hasMultipleValues - ) { - this.ensureParametersConsistency(this); // reset existing variable param - } - break; + if (oldMode === ParamValueMode.CALCUL) { + if (propagateToCalculatedParam) { + // Set default calculated parameter, only if previous CALC param was + // manually set to something else than CALC + if (this.parentComputeNode && this.parentComputeNode instanceof Nub) { + this.parentComputeNode.resetDefaultCalculatedParam(this); } - break; - - case ParamValueMode.LINK: // ancien état - switch (newMode) { - case ParamValueMode.MINMAX: // nouvel état - case ParamValueMode.LISTE: - this.ensureParametersConsistency(this, ParamValueMode.CALCUL); - break; - - case ParamValueMode.CALCUL: // nouvel état - this.ensureParametersConsistency(this, [ ParamValueMode.MINMAX, ParamValueMode.LISTE ]); - break; - } - break; - - case ParamValueMode.CALCUL: // ancien état - switch (newMode) { - case ParamValueMode.SINGLE: // nouvel état - break; - - case ParamValueMode.MINMAX: // nouvel état - case ParamValueMode.LISTE: - this.ensureParametersConsistency(this); - break; - - case ParamValueMode.LINK: // nouvel état - if ( - this.isReferenceDefined() - && this.hasMultipleValues - ) { - this.ensureParametersConsistency(this); // reset existing variable param - } - break; - } - - if (propagateToCalculatedParam) { - // Set default calculated parameter, only if previous CALC param was - // manually set to something else than CALC - if (this.parentComputeNode && this.parentComputeNode instanceof Nub) { - this.parentComputeNode.resetDefaultCalculatedParam(this); - } - } - + } + } else if (newMode === ParamValueMode.CALCUL) { + // set old CALC param to SINGLE mode + if (this.parentComputeNode && this.parentComputeNode instanceof Nub) { + this.parentComputeNode.unsetCalculatedParam(this); + } } // set new mode @@ -403,7 +365,7 @@ export class ParamDefinition implements INamedIterableValues, IObservable { ); break; case ParamValueMode.LISTE: - defined = (this.valueList.length > 0 && this.valueList[0] !== undefined); + defined = (this.valueList && this.valueList.length > 0 && this.valueList[0] !== undefined); break; case ParamValueMode.CALCUL: if (this.parentNub && this.parentNub.result && this.parentNub.result.nbResultElements > 0) { @@ -500,6 +462,15 @@ export class ParamDefinition implements INamedIterableValues, IObservable { return this.paramValues.singleValue; } + /** + * Returns values as a number list, for LISTE and MINMAX modes; + * in MINMAX mode, infers the list from min/max/step values + */ + public getInferredValuesList() { + this.checkValueMode([ParamValueMode.LISTE, ParamValueMode.MINMAX, ParamValueMode.LINK]); + return this.paramValues.getInferredValuesList(); + } + /** * Magic method to define current values into Paramvalues set; defines the mode * accordingly by detecting values nature @@ -1007,6 +978,10 @@ export class ParamDefinition implements INamedIterableValues, IObservable { } } + public getExtendedValuesIterator(size: number): INumberIterator { + return this._paramValues.getValuesIterator(false, size); + } + /** * Returns true if there are more than 1 value associated to this parameter; * might be its own values (MINMAX / LISTE mode), or targetted values (LINK mode) @@ -1076,17 +1051,6 @@ export class ParamDefinition implements INamedIterableValues, IObservable { return res; } - /** - * Asks parent Nub if any to ensure parameters consistency - */ - protected ensureParametersConsistency(sourceParam: ParamDefinition, - exceptMode: ParamValueMode|ParamValueMode[] = [] - ) { - if (this.parentComputeNode && this.parentComputeNode instanceof Nub) { - this.parentComputeNode.ensureParametersConsistency(sourceParam, exceptMode); - } - } - /** * notification envoyée après la modification de la valeur du paramètre */ diff --git a/src/param/param-value-iterator.ts b/src/param/param-value-iterator.ts index c11d0a32257055fb72917fdaa71bc2f6948f480d..dfc309826f2f593b054fd8054885649668ce87f8 100644 --- a/src/param/param-value-iterator.ts +++ b/src/param/param-value-iterator.ts @@ -1,5 +1,6 @@ import { INamedObject, IObjectWithFamily } from "../jalhyd_object"; import { ArrayReverseIterator } from "../util/iterator"; +import { ExtensionStrategy } from "./param-definition"; import { ParamValueMode } from "./param-value-mode"; import { ParamValues } from "./param-values"; @@ -56,27 +57,39 @@ export interface INamedIterableValues extends INamedObject, IObjectWithFamily, I * itérateur sur les (ou la) valeurs prises par un ParamValues */ export class ParamValueIterator implements INumberIterator { - /** - * paramètre à itérer - */ + + /** paramètre à itérer */ private _param: ParamValues; /** - * true si les valeurs sont fournies de max à min (ParamValueMode.MINMAX) + * true si les valeurs sont fournies de max à min (ParamValueMode.MINMAX); + * utilisé uniquement par Remous */ private _reverse: boolean; - /** - * valeur courante - */ + /** length to extend the values series to, depending on _param ExtensionStrategy */ + private _extendTo: number; + + /** valeur courante */ private _current: number; + /** + * index sur les valeurs définies (et non sur les valeurs étendues): en mode LISTE, + * nombre de valeurs actuellement produites; en mode MINMAX, valeur courante (!) + */ private _index: number; - constructor(prm: ParamValues, reverse: boolean = false) { + /** + * index sur les valeurs étendues (lorsque plusieurs paramètres varient): en mode MINMAX, + * nombre de valeurs actuellement produites, à comparer à this._extendTo; en mode LISTE, + * index de la valeur courante à répéter (!) + */ + private _xindex: number; + + constructor(prm: ParamValues, reverse: boolean = false, extendTo: number) { prm.check(); this._param = prm; - this.reset(reverse); + this.reset(reverse, extendTo); } /** @@ -91,8 +104,10 @@ export class ParamValueIterator implements INumberIterator { return length; } - public reset(reverse: boolean) { + public reset(reverse: boolean, extendTo?: number) { this._reverse = reverse; + this._extendTo = extendTo; + this._xindex = 0; switch (this._param.valueMode) { case ParamValueMode.SINGLE: @@ -116,27 +131,6 @@ export class ParamValueIterator implements INumberIterator { throw new Error(`ParamValueIterator : mode de génération de valeurs ${ParamValueMode[this._param.valueMode]} incorrect`); } } - - public get hasNext(): boolean { - switch (this._param.valueMode) { - - case ParamValueMode.SINGLE: - return this._index === 0; - - case ParamValueMode.MINMAX: - const end = this._reverse ? - this._index < this._param.min - this._param.step * 1E-7 : - this._index > this._param.max + this._param.step * 1E-7; - return !end; - - case ParamValueMode.LISTE: - return this._index < this._param.valueList.length; - - default: - throw new Error(`ParamValueIterator.hasNext() : erreur interne`); - } - } - public next(): IteratorResult<number> { switch (this._param.valueMode) { @@ -144,6 +138,7 @@ export class ParamValueIterator implements INumberIterator { if (this.hasNext) { this._current = this._param.singleValue; this._index++; + this._xindex ++; return { done: false, value: this._current @@ -156,40 +151,102 @@ export class ParamValueIterator implements INumberIterator { } case ParamValueMode.MINMAX: - this._current = this._index; - if (this.hasNext) { + if (this.hasNextWithoutExtension) { // default case + this._current = this._index; if (this._reverse) { this._index -= this._param.step; } else { this._index += this._param.step; } + this._xindex ++; // count values for possible extension return { done: false, value: this._current }; - } else { - return { - done: true, - value: undefined - }; + } else { // no more real values + if (this._extendTo && this.hasNext) { + // extend + this._xindex ++; + switch (this._param.extensionStrategy) { + case ExtensionStrategy.REPEAT_LAST: + // repeat last real value (do not change this._current) + return { + done: false, + value: this._current + }; + + case ExtensionStrategy.RECYCLE: + // loop over real values + if ( // end reached + this._reverse ? + this._index < this._param.min - this._param.step * 1E-7 : + this._index > this._param.max + this._param.step * 1E-7 + ) { + this._index = this._reverse ? this._param.max : this._param.min; + } + this._current = this._index; + if (this._reverse) { + this._index -= this._param.step; + } else { + this._index += this._param.step; + } + return { + done: false, + value: this._current + }; + } + } else { + return { + done: true, + value: undefined + }; + } } case ParamValueMode.LISTE: - if (this.hasNext) { - this._current = this._param.valueList[this._index++]; + if (this.hasNextWithoutExtension) { // default case + this._current = this._param.valueList[this._index++]; // what about _reverse ? + this._xindex ++; // count values for possible extension return { done: false, value: this._current }; - } else { - return { - done: true, - value: undefined - }; + } else { // no more real values + if (this._extendTo && this.hasNext) { + // extend + this._index ++; + switch (this._param.extensionStrategy) { + case ExtensionStrategy.REPEAT_LAST: + // repeat last real value (do not change this._current) + return { + done: false, + value: this._current + }; + + case ExtensionStrategy.RECYCLE: + // loop over real values + if ( + this._xindex === undefined + || this._xindex === this._param.valueList.length + ) { + this._xindex = 0; + } + this._current = this._param.valueList[this._xindex++]; + return { + done: false, + value: this._current + }; + } + } else { + return { + done: true, + value: undefined + }; + } } default: - throw new Error(`ParamValueIterator.next() : erreur interne`); + throw new Error(`ParamValueIterator.next() : internal error`); } } @@ -202,6 +259,47 @@ export class ParamValueIterator implements INumberIterator { public [Symbol.iterator](): IterableIterator<number> { return this; } + + public get hasNext(): boolean { + return this.hasNextValue(); + } + + protected get hasNextWithoutExtension() { + return this.hasNextValue(true); + } + + /** + * Returns true if iterator has at least one more value + * @param ignoreExtension if true, will consider only real values (those that were + * set up) and ignore extended values (when multiple parameters are varying) + */ + protected hasNextValue(ignoreExtension: boolean = false): boolean { + switch (this._param.valueMode) { + + case ParamValueMode.SINGLE: + return this._index === 0; + + case ParamValueMode.MINMAX: + if (this._extendTo && !ignoreExtension) { + return this._xindex < this._extendTo; + } else { + const end = this._reverse ? + this._index < this._param.min - this._param.step * 1E-7 : + this._index > this._param.max + this._param.step * 1E-7; + return !end; + } + + case ParamValueMode.LISTE: + if (this._extendTo && !ignoreExtension) { + return this._index < this._extendTo; + } else { + return this._index < this._param.valueList.length; + } + + default: + throw new Error(`ParamValueIterator.hasNext() : internal error`); + } + } } /** diff --git a/src/param/param-values.ts b/src/param/param-values.ts index 9d850c7d16bcf7c042d6e4f298ac74bf15b6b37b..9da01d09f7aa35689daa38ac535fe324b3c1b248 100644 --- a/src/param/param-values.ts +++ b/src/param/param-values.ts @@ -1,3 +1,4 @@ +import { ExtensionStrategy } from "./param-definition"; import { INumberIterator, IterableValues, ParamValueIterator } from "./param-value-iterator"; import { ParamValueMode } from "./param-value-mode"; @@ -8,11 +9,12 @@ import { ParamValueMode } from "./param-value-mode"; */ export class ParamValues implements IterableValues { - /** - * usually set by enclosing ParamDefinition - */ + /** usually set by enclosing ParamDefinition */ public valueMode: ParamValueMode; + /** usually set by enclosing ParamDefinition */ + public extensionStrategy: ExtensionStrategy; + /** valeur courante (éventuellement non définie) indépendemment du mode */ public currentValue: number; @@ -104,14 +106,34 @@ export class ParamValues implements IterableValues { } } + /** + * Returns values as a number list, for LISTE and MINMAX modes; + * in MINMAX mode, infers the list from min/max/step values + */ + public getInferredValuesList() { + if (this.valueMode === ParamValueMode.LISTE) { + return this.valueList; + } + if (this.valueMode === ParamValueMode.MINMAX) { + const values = [ this.min ]; + let latestVal = this.min + this.step; + while (latestVal <= this.max) { + values.push(latestVal); + latestVal += this.step; + } + return values; + } + throw new Error("ParamValues.getInferredValuesList() : incorrect value mode" + ParamValueMode[this.valueMode]); + } + // -- iterator-related methods /** * crée un ParamValueIterator * @param reverse true si on veut itérer max->min ou depuis la fin de la liste */ - public getValuesIterator(reverse: boolean = false): INumberIterator { - return new ParamValueIterator(this, reverse); + public getValuesIterator(reverse: boolean = false, extendTo?: number): INumberIterator { + return new ParamValueIterator(this, reverse, extendTo); } // interface IterableValues @@ -136,11 +158,11 @@ export class ParamValues implements IterableValues { } } - public initValuesIterator(reverse: boolean = false): INumberIterator { + public initValuesIterator(reverse: boolean = false, extendTo?: number): INumberIterator { switch (this.valueMode) { case ParamValueMode.LISTE: case ParamValueMode.MINMAX: - this._iterator = this.getValuesIterator(reverse); + this._iterator = this.getValuesIterator(reverse, extendTo); break; default: diff --git a/src/section/section_parametree.ts b/src/section/section_parametree.ts index d09e870807ace50d738993de9f45d0ab78928df2..b88b68ae04ecbf68a3145cf18a9c325ba95195cb 100644 --- a/src/section/section_parametree.ts +++ b/src/section/section_parametree.ts @@ -69,67 +69,6 @@ export class SectionParametree extends SectionNub { } } - public CalcSerie(rInit?: number, sDonnee?: string): Result { - - this.triggerChainCalculation(); - - let variatedParam: ParamDefinition; - let variatedValues: ParamValues; - - for (const p of this.parameterIterator) { - // checks which values are variating, if any - switch (p.valueMode) { - case ParamValueMode.SINGLE: - case ParamValueMode.CALCUL: - break; - - case ParamValueMode.LISTE: - case ParamValueMode.MINMAX: - variatedParam = this.setVariatedValues(p, variatedParam); - break; - - case ParamValueMode.LINK: - if ( - p.isReferenceDefined() - && p.referencedValue.hasMultipleValues() - ) { - variatedParam = this.setVariatedValues(p, variatedParam); - } - break; - - default: - // tslint:disable-next-line:max-line-length - throw new Error(`CalcSerie() : valeur de ParamValueMode ${ParamValueMode[p.valueMode]} non prise en charge`); - } - } - - if (variatedParam === undefined) { - this.Calc(); // résultat dans this._result - } else { - // extract variated values from variated Parameter - // (in LINK mode, proxies to target data) - variatedValues = variatedParam.paramValues; - - const res = new Result(undefined, this); - variatedValues.initValuesIterator(false); - while (variatedValues.hasNext) { - variatedValues.next(); - - this.Calc(); // résultat dans this._result - if (this._result.ok) { - res.addResultElement(this._result.resultElement); - res.addLog(this._result.log); - } - res.globalLog.addLog(this._result.globalLog); - } - this._result = res; - - } - - this.notifyResultUpdated(); - return this._result; - } - /** * Aucune variable à calculer plus que les autres, on stocke toutes les * valeurs des variables à calcul dans les résultats complémentaires @@ -198,6 +137,19 @@ export class SectionParametree extends SectionNub { return this._result; } + // calculated param is always "Y" + protected findCalculatedParameter(sDonnee: any): any { + return undefined; + } + + // calculated param is always "Y" + protected doCalc(computedSymbol?: any, rInit?: number) { + return this.Calc(); + } + + // does nothing or else tests break !? + protected copySingleValuesToSandboxValues() { } + // tslint:disable-next-line:no-empty protected setParametersCalculability(): void {} diff --git a/src/structure/structure.ts b/src/structure/structure.ts index 2547d78fb204f3873e8b380469213b5d218e4ebf..123d0490d8b9cf906af2cc109b43fa505c421cf9 100644 --- a/src/structure/structure.ts +++ b/src/structure/structure.ts @@ -106,9 +106,9 @@ export abstract class Structure extends Nub { * Forwards to parent, that has vsibility over * all the parameters, including the Structure ones */ - public ensureParametersConsistency(sourceParam: ParamDefinition, exceptMode: ParamValueMode|ParamValueMode[] = []) { + public unsetCalculatedParam(except: ParamDefinition) { if (this.parent) { - this.parent.ensureParametersConsistency(sourceParam, exceptMode); + this.parent.unsetCalculatedParam(except); } } @@ -137,9 +137,9 @@ export abstract class Structure extends Nub { * Forwards to parent, that has vsibility over * all the parameters, including the Structure ones */ - public findFirstSingleParameter(otherThan?: ParamDefinition) { + public findFirstCalculableParameter(otherThan?: ParamDefinition) { if (this.parent) { - return this.parent.findFirstSingleParameter(otherThan); + return this.parent.findFirstCalculableParameter(otherThan); } return undefined; }