diff --git a/spec/regime_uniforme/regime_uniforme_puissance.spec.ts b/spec/regime_uniforme/regime_uniforme_puissance.spec.ts index 07d90ab066aa48dd0d26cfc5efcae7fc38323e87..a69baf9ee7597c37dc1a595d7bd8d3717e3d7e2a 100644 --- a/spec/regime_uniforme/regime_uniforme_puissance.spec.ts +++ b/spec/regime_uniforme/regime_uniforme_puissance.spec.ts @@ -196,7 +196,7 @@ describe("Class RegimeUniforme / section puissance :", () => { const res: Result = ru.Calc("Ks", 5000000); expect(res.vCalc).toBeUndefined(); - expect(res.code).toBe(MessageCode.ERROR_DICHO_INITVALUE_HIGH); + expect(res.code).toBe(MessageCode.ERROR_DICHO_TARGET_TOO_LOW); }); it("Ks should be undefined", () => { @@ -215,7 +215,7 @@ describe("Class RegimeUniforme / section puissance :", () => { const res: Result = ru.Calc("Ks", 1e-8); expect(res.vCalc).toBeUndefined(); - expect(res.code).toBe(MessageCode.ERROR_DICHO_INITVALUE_LOW); + expect(res.code).toBe(MessageCode.ERROR_DICHO_TARGET_TOO_HIGH); }); it("If should be 0.001", () => { diff --git a/spec/structure/functions.ts b/spec/structure/functions.ts index f4dbdc955361da332c614d22c4bd8ff807fa8601..9b9fbb941832a1a4a3d7d9f6dc87089e2e619563 100644 --- a/spec/structure/functions.ts +++ b/spec/structure/functions.ts @@ -41,7 +41,7 @@ export function itCalcQ( let res: Result; // struct.debug("struct.Calc(Q)=" + res.vCalc); describe("itCalcQ", () => { - beforeAll( () => { + beforeEach( () => { struct.prms.Z1.v = Z1; struct.prms.W.v = W; res = struct.Calc("Q"); diff --git a/spec/structure/structure_cem88v.spec.ts b/spec/structure/structure_cem88v.spec.ts index 6e15f5d1630c8c37417a1d5c48711664ab66b816..f450d2b56e155f0cf98ff14892d534ddb8d9d5b5 100644 --- a/spec/structure/structure_cem88v.spec.ts +++ b/spec/structure/structure_cem88v.spec.ts @@ -6,15 +6,20 @@ */ // import { describe, expect, it, xdescribe } from "../mock_jasmine"; +import { CreateStructure, LoiDebit, MessageCode, Result } from "../../src/index"; import { RectangularStructureParams } from "../../src/structure/rectangular_structure_params"; import { StructureFlowMode, StructureFlowRegime } from "../../src/structure/structure"; import { StructureWeirCem88v } from "../../src/structure/structure_cem88v"; import { itCalcQ } from "./functions"; -const structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0); -const structTest: StructureWeirCem88v = new StructureWeirCem88v(structPrm, false); +let structPrm: RectangularStructureParams = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0); +let structTest: StructureWeirCem88v = new StructureWeirCem88v(structPrm, false); describe("Class StructureWeirCem88v: ", () => { + beforeEach( () => { + structPrm = new RectangularStructureParams(1, 0, 1, 1, 2, 0.6, 0); + structTest = new StructureWeirCem88v(structPrm, false); + }); describe("Calcul Q avec W croissant: ", () => { const W: number[] = [0.000000, 0.100000, 0.200000, 0.300000, 0.400000, 0.500000, 0.600000, 0.700000, 0.800000, 0.900000, 1.000000, 1.100000, 1.200000, 1.300000]; @@ -52,4 +57,13 @@ describe("Class StructureWeirCem88v: ", () => { itCalcQ(structTest, h1[i], W, Q[i], mode[i], regime[i]); } }); + describe("Calcul W avec débit trop élevé", () => { + it("Calc(W) should return error", () => { + const s = CreateStructure(LoiDebit.GateCem88v); + s.prms.Q.singleValue = 6; + s.calculatedParam = s.prms.W; + const res: Result = s.CalcSerie(); + expect(res.code).toBe(MessageCode.ERROR_DICHO_TARGET_TOO_HIGH) + }); + }); }); diff --git a/src/dichotomie.ts b/src/dichotomie.ts index edaab56e446f42ec15223afb94ccbb5b15f6484e..27a1059ba7dc5f5800a8fefc0a8a4c9fffcab6db 100644 --- a/src/dichotomie.ts +++ b/src/dichotomie.ts @@ -86,14 +86,14 @@ class SearchInterval extends Interval { return super.toString() + " step=" + this._step; } - private updateTargets() { + public updateTargets() { let t1 = this.targets.val1; - if (t1 === undefined) { + if (t1 === undefined || isNaN(t1)) { t1 = this._dicho.CalculX(this.val1).vCalc; } let t2 = this.targets.val2; - if (t2 === undefined) { + if (t2 === undefined || isNaN(t2)) { t2 = this._dicho.CalculX(this.val2).vCalc; } this.targets.setValues(t1, t2); @@ -117,7 +117,7 @@ export class Dichotomie extends Debug { /** * nombre d'étapes de recherche de l'intervalle de départ */ - private _startIntervalMaxSteps = 100; + private _startIntervalMaxSteps = 60; /** * nombre d'itérations maxi pour la recherche dichotomique @@ -199,10 +199,17 @@ export class Dichotomie extends Debug { const r = this.getStartInterval(rTarget, rInit); if (r.ok) { - const interv: SearchInterval = r.intSearch; + const inter: SearchInterval = r.intSearch; this._currentIterations = 0; // Dichotomie - return this.dichoSearch(rTarget, rTol, interv.min, interv.max, interv.targetLower, interv.targetUpper); + return this.dichoSearch( + rTarget, + rTol, + inter.min, + inter.max, + inter.targets.getVal(inter.minIndex), + inter.targets.getVal(inter.maxIndex) + ); } else { return new Result(r.res); } @@ -249,11 +256,10 @@ export class Dichotomie extends Debug { let n = 0; let ok: boolean = false; do { - const inters: Interval = intSearch.intersect(intMax); - if (inters.length === 0) { + intSearch.setInterval(intSearch.intersect(intMax)); + if (intSearch.length === 0) { break; } - intSearch.setInterval(inters); if (intSearch.hasTargetValue(rTarget)) { ok = true; break; @@ -261,7 +267,6 @@ export class Dichotomie extends Debug { intSearch.growStep(2); intSearch.next(); } while (n++ < this._startIntervalMaxSteps); - return { ok, intSearch }; } @@ -293,36 +298,26 @@ export class Dichotomie extends Debug { } // initialisation de l'intervalle de recherche - let intSearch: SearchInterval = new SearchInterval(this, rInit - step / 2, rInit + step / 2, step); - // au cas où l'on sorte du domaine de la variable de la fonction - intSearch.setInterval(intSearch.intersect(intMax)); - + const intSearch1: SearchInterval = new SearchInterval(this, rInit - step / 2, rInit + step / 2, step); // sens de variation de la fonction const inc = this.isIncreasingFunction(rInit, intMax); - const initTarget = this.CalculX(rInit).vCalc; - // if (initTarget > rTarget && inc || initTarget < rTarget && !inc) - if (BoolIdentity(initTarget > rTarget, inc)) { - intSearch.reverse(); + if (BoolIdentity(this.CalculX(rInit).vCalc > rTarget, inc)) { + intSearch1.reverse(); // par ex, la fonction est croissante et la valeur initiale // de la variable a une image par la fonction > valeur cible } // on cherche dans une première direction - - let a = this.searchTarget(rTarget, intSearch, intMax); + let a = this.searchTarget(rTarget, intSearch1, intMax); if (a.ok) { return a; } // il se peut que la fonction ne soit pas monotone et qu'il faille chercher dans l'autre direction - - const oldStepSign = intSearch.step > 0 ? 1 : -1; - intSearch = new SearchInterval(this, rInit + step / 2, rInit + step, step * -oldStepSign); - // au cas où l'on sorte du domaine de la variable de la fonction - intSearch.setInterval(intSearch.intersect(intMax)); - - a = this.searchTarget(rTarget, intSearch, intMax); + const oldStepSign = intSearch1.step > 0 ? 1 : -1; + const intSearch2 = new SearchInterval(this, rInit + step / 2, rInit + step, step * -oldStepSign); + a = this.searchTarget(rTarget, intSearch2, intMax); if (a.ok) { return a; } @@ -359,17 +354,39 @@ export class Dichotomie extends Debug { res.extraVar.variableInterval = intMax.toString(); res.extraVar.variableSymbol = this._paramX.symbol; // symbole de la variable d'entrée de la fonction } else { - // if (intSearch.step < 0) - if (BoolIdentity(initTarget > rTarget, inc)) { - res = new Message(MessageCode.ERROR_DICHO_INITVALUE_HIGH); + // Fusion des infos des deux intervalles explorés + const intFus: number[] = []; // Signification des indices : 0,1 : minmax target; 2, 3 : variables associées + if (isNaN(intSearch1.targets.max) || isNaN(intSearch2.targets.max)) { + // bug targets en NaN en prod mais pas en debug pas à pas en explorant les variables + intSearch1.updateTargets(); + intSearch2.updateTargets(); + } + if (intSearch1.targets.max > intSearch2.targets.max) { + intFus[1] = intSearch1.targets.max; + intFus[3] = intSearch1.getVal(intSearch1.targets.maxIndex); + } else { + intFus[1] = intSearch2.targets.max; + intFus[3] = intSearch2.getVal(intSearch2.targets.maxIndex); + } + if (intSearch1.targets.min < intSearch2.targets.min) { + intFus[0] = intSearch1.targets.min; + intFus[2] = intSearch1.getVal(intSearch1.targets.minIndex); + } else { + intFus[0] = intSearch2.targets.min; + intFus[2] = intSearch2.getVal(intSearch2.targets.minIndex); + } + if (intFus[1] < rTarget) { + res = new Message(MessageCode.ERROR_DICHO_TARGET_TOO_HIGH); + res.extraVar.extremeTarget = intFus[1]; + res.extraVar.variableExtremeValue = intFus[3]; } else { - res = new Message(MessageCode.ERROR_DICHO_INITVALUE_LOW); + res = new Message(MessageCode.ERROR_DICHO_TARGET_TOO_LOW); + res.extraVar.extremeTarget = intFus[0]; + res.extraVar.variableExtremeValue = intFus[2]; } res.extraVar.variableSymbol = this._paramX.symbol; // symbole de la variable de la fonction - res.extraVar.variableInitValue = rInit; // valeur initiale de la variable res.extraVar.targetSymbol = this.analyticalSymbol; // symbole de la variable calculée par la fonction res.extraVar.targetValue = rTarget; // valeur cible pour la fonction - res.extraVar.initTarget = initTarget; // valeur de la fonction pour la valeur initiale de la variable } return { ok: false, res }; diff --git a/src/util/interval.ts b/src/util/interval.ts index dd3fc9e3d2fe2b166ce99a3b5a889c6c9b361356..11532acd10e3f71776c6b246e3cc8cf415d63a13 100644 --- a/src/util/interval.ts +++ b/src/util/interval.ts @@ -61,4 +61,38 @@ export class Interval { public toString(): string { return "[" + this.min + "," + this.max + "]"; } + + public getVal(i: number): number { + if (i < 1 || i > 2) { throw new Error("Interval getVal n'accepte que 1 ou 2 en argument"); } + if (i === 1) { + return this.val1; + } else { + return this.val2; + } + } + + public setVal(i: number, val: number) { + if (i < 1 || i > 2) { throw new Error("Interval getVal n'accepte que 1 ou 2 en argument"); } + if (i === 1) { + this.val1 = val; + } else { + this.val2 = val; + } + } + + get minIndex(): number { + if (this.val1 === this.min) { + return 1; + } else { + return 2; + } + } + + get maxIndex(): number { + if (this.val1 === this.max) { + return 1; + } else { + return 2; + } + } } diff --git a/src/util/message.ts b/src/util/message.ts index 0fa570d1bd690810f2caff3f19966471043a31f5..52e3730ecf6ca1d7bde6a969a0c2f67f0ee69a73 100644 --- a/src/util/message.ts +++ b/src/util/message.ts @@ -5,16 +5,16 @@ export enum MessageCode { ERROR_OK, /** - * la dichotomie n'a pas pu trouver automatiquement d'intervalle de départ - * car la valeur initiale de la variable est trop haute + * La dichotomie n'a pas trouvé de solution dans sa recherche d'intervalle: + * La valeur cible est trop élevée */ - ERROR_DICHO_INITVALUE_HIGH, + ERROR_DICHO_TARGET_TOO_HIGH, /** - * la dichotomie n'a pas pu trouver automatiquement d'intervalle de départ - * car la valeur initiale de la variable est trop basse + * La dichotomie n'a pas trouvé de solution dans sa recherche d'intervalle: + * La valeur cible est trop basse */ - ERROR_DICHO_INITVALUE_LOW, + ERROR_DICHO_TARGET_TOO_LOW, /** * la dichotomie n'a pas pu trouver automatiquement d'intervalle de départ