From 2ed395b98082c49965c7033cc3be8220e2be61c3 Mon Sep 17 00:00:00 2001 From: David Dorchies <david.dorchies@irstea.fr> Date: Wed, 22 Nov 2017 00:20:15 +0100 Subject: [PATCH] =?UTF-8?q?#6=20Ajout=20de=20l'=C3=A9quation=20CEM88d=20av?= =?UTF-8?q?ec=20tests=20OK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/mock_jasmine.ts | 56 +++++++++++++++++++++++++ spec/structure/structure_cem88d.spec.ts | 46 +++++++++++++++----- spec/structure/test_structure_cem88d.ts | 48 +++++++++++++++++++++ src/base.ts | 5 ++- src/structure/structure.ts | 31 ++++++++++++-- src/structure/structure_cem88d.ts | 26 ++++++++---- 6 files changed, 188 insertions(+), 24 deletions(-) create mode 100644 spec/mock_jasmine.ts create mode 100644 spec/structure/test_structure_cem88d.ts diff --git a/spec/mock_jasmine.ts b/spec/mock_jasmine.ts new file mode 100644 index 00000000..3a9c2f85 --- /dev/null +++ b/spec/mock_jasmine.ts @@ -0,0 +1,56 @@ +/** + * Mock fonction describe de Jasmine + * @param sTxt Texte de la suite de test + * @param fFun Fonction de la suite de test + */ +export function describe(sTxt: string, fFun: Function) { + //console.group(); + console.log(sTxt); + fFun(); + //console.groupEnd(); +} + +/** + * Mock fonction it de jasmine + * @param sTxt Texte à afficher pour la spec + * @param fFun Function à lancer pour la spec + */ +export function it(sTxt: string, fFun: Function) { + console.log(sTxt); + fFun(); +} + +/** + * Mock expect et toBeCloseTo de Jasmine. + * Ne fonctionne pas à cause de this = undefined dans le contexte "use strict" + */ +export function expect(obj: Object) { + this.testResult = obj; + + this.toBeCloseTo = function(expected: number, precision: number) { + var pow = Math.pow(10, precision + 1); + var delta = Math.abs(expected - this.testResult); + var maxDelta = Math.pow(10, -precision) / 2; + if (Math.round(delta * pow) / pow > maxDelta) { + console.error("Expected "+this.testResult+" to be close to "+expected+","+precision); + } + return this; + }; + return this; +} + +/** + * Mock de la function chainée à expect de test d'une valeur à un epsilon près + * @param actual Valeur numérique sortie du test + * @param expected Valeur numérique attendue + * @param precision Précision attendue (nombre de chiffre après la virgule) + */ +export function toBeCloseTo (actual: number, expected: number, precision: number) { + var pow = Math.pow(10, precision + 1); + var delta = Math.abs(expected - actual); + var maxDelta = Math.pow(10, -precision) / 2; + if (Math.round(delta * pow) / pow > maxDelta) { + console.error("Expected "+actual+" to be close to "+expected+","+precision); + } + return this; +}; diff --git a/spec/structure/structure_cem88d.spec.ts b/spec/structure/structure_cem88d.spec.ts index defd90c8..901b8327 100644 --- a/spec/structure/structure_cem88d.spec.ts +++ b/spec/structure/structure_cem88d.spec.ts @@ -4,19 +4,43 @@ import { StructureCem88d, RectangularStructureParams } from "../../src/structure import { Result } from "../../src/base"; import { precDigits } from "../nubtest"; -let structPrm: RectangularStructureParams = new RectangularStructureParams(1, undefined, 1, 2, 0.6, 0); -let structTest: StructureCem88d = new StructureCem88d(structPrm, false); - -let resultTesth1FnW: number[] = [Infinity, 3.603062, 1.560872, 1.323331, 1.154102, 1.073632, 1.047438, 1.035118, 1.027086, 1.021649, 1.021305]; +let structPrm: RectangularStructureParams = new RectangularStructureParams(1, 1, 1, 2, 0.6, 0); +let structTest: StructureCem88d = new StructureCem88d(structPrm, true); describe('Class StructureCem88d: ', () => { - describe('Calcul h1 avec W croissant: ', () => { - for(let iW = 0; iW <= 10; iW++ ) { - structTest.prms.W.v = iW / 10 ; - it('h1(W='+structTest.prms.W.v+') should be '+resultTesth1FnW[iW], () => { - console.log('h1(W='+structTest.prms.W.v+') should be '+resultTesth1FnW[iW]); - expect(structTest.Calc('h1').vCalc).toBeCloseTo(resultTesth1FnW[iW],precDigits); - }); + function itCalcQ(structTest:StructureCem88d, h1:number, W:number, Q:number) { + it('Q(h1='+h1+',W='+W+') should be '+Q, () => { + structTest.prms.h1.v = h1; + structTest.prms.W.v = W; + expect(structTest.Calc('Q').vCalc).toBeCloseTo(Q,precDigits); + }); + } + + describe('Calcul Q avec W croissant: ', () => { + let 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]; + let h1: number = 1.200000; + let Q: number[] = [0.000000,0.617586,1.235173,1.852759,2.470345,3.087931,3.705518,4.296608,4.831177,5.302464,5.700445,6.007777,6.175863,6.175863]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1, W[i], Q[i]); + } + }); + describe('Calcul Q en charge avec h1 croissant: ', () => { + let W: number = 0.6; + let h1: number[] =[1.100000,1.300000,1.500000]; + let Q: number[] =[2.620197,4.450866,5.226583]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1[i], W, Q[i]); + } + }); + describe('Calcul Q a surface libre avec h1 croissant: ', () => { + let W: number = Infinity; + let h1: number[] =[1.100000,1.500000]; + let Q: number[] =[4.366994,9.764896]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1[i], W, Q[i]); } }); }); diff --git a/spec/structure/test_structure_cem88d.ts b/spec/structure/test_structure_cem88d.ts new file mode 100644 index 00000000..34f24d4a --- /dev/null +++ b/spec/structure/test_structure_cem88d.ts @@ -0,0 +1,48 @@ +import { StructureCem88d, RectangularStructureParams } from "../../src/structure/structure_cem88d"; +import { Result } from "../../src/base"; +import { precDigits } from "../nubtest"; +import { describe, it, toBeCloseTo } from "../mock_jasmine" + +//expect(1).toBeCloseTo(1,3); + +let structPrm: RectangularStructureParams = new RectangularStructureParams(1, 1, 1, 2, 0.6, 0); +let structTest: StructureCem88d = new StructureCem88d(structPrm, true); + +describe('Class StructureCem88d: ', () => { + function itCalcQ(structTest:StructureCem88d, h1:number, W:number, Q:number) { + it('Q(h1='+h1+',W='+W+') should be '+Q, () => { + structTest.prms.h1.v = h1; + structTest.prms.W.v = W; + toBeCloseTo(structTest.Calc('Q').vCalc, Q, precDigits); + }); + } + + describe('Calcul Q avec W croissant: ', () => { + let 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]; + let h1: number = 1.200000; + let Q: number[] = [0.000000,0.617586,1.235173,1.852759,2.470345,3.087931,3.705518,4.296608,4.831177,5.302464,5.700445,6.007777,6.175863,6.175863]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1, W[i], Q[i]); + } + }); + describe('Calcul Q en charge avec h1 croissant: ', () => { + let W: number = 0.6; + let h1: number[] =[1.100000,1.300000,1.500000]; + let Q: number[] =[2.620197,4.450866,5.226583]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1[i], W, Q[i]); + } + }); + describe('Calcul Q a surface libre avec h1 croissant: ', () => { + let W: number = Infinity; + let h1: number[] =[1.100000,1.500000]; + let Q: number[] =[4.366994,9.764896]; + + for(let i = 0; i < Q.length; i++ ) { + itCalcQ(structTest, h1[i], W, Q[i]); + } + }); +}); + diff --git a/src/base.ts b/src/base.ts index 8b873195..9930687e 100644 --- a/src/base.ts +++ b/src/base.ts @@ -12,9 +12,10 @@ export class Result { private _message: Message; - constructor(v: number, e: Message = undefined) { + constructor(v: number, m: Message = undefined, e: { [key: string]: any } = {}) { this._vCalc = v; - this._message = e; + this._message = m; + this.extraVar = e; }; get vCalc() { return this._vCalc; } diff --git a/src/structure/structure.ts b/src/structure/structure.ts index 2b3937e1..a8211a1f 100644 --- a/src/structure/structure.ts +++ b/src/structure/structure.ts @@ -4,7 +4,7 @@ import { Result } from "../base"; import { ComputeNodeType, ParamDefinition, ParamDomain, ParamDomainValue, ParamCalculability, ParamsEquation } from "../param"; import { Nub } from "../nub"; - +import { Message } from "../util/message"; /** * Common parameters of hydraulic structure equations @@ -98,8 +98,14 @@ export abstract class Structure extends Nub { * Give the flow mode : weir or orifice flow */ protected getFlowMode(): StructureFlowMode { - if (this.prms.h1.v >= this.prms.W.v) return StructureFlowMode.ORIFICE; - return StructureFlowMode.WEIR; + if (this.prms.h1.v > this.prms.W.v) { + this.debug("Structure.getFlowRegime(h1="+this.prms.h1.v+",W="+this.prms.W.v+")=ORIFICE"); + return StructureFlowMode.ORIFICE; + } else { + this.debug("Structure.getFlowRegime(h1="+this.prms.h1.v+",W="+this.prms.W.v+")=WEIR"); + return StructureFlowMode.WEIR; + } + } @@ -111,12 +117,15 @@ export abstract class Structure extends Nub { // Orifice have three flow regimes: free, partially submerged and (totally) submerged if(this.prms.h2.v <= 2/3*this.prms.h1.v) { // free flow for both weirs and orifices + this.debug("Structure.getFlowRegime(h1="+this.prms.h1.v+",h2="+this.prms.h2.v+",W="+this.prms.W.v+")=FREE"); return StructureFlowRegime.FREE; } else if(this.prms.h1.v > this.prms.W.v && this.prms.h2.v < (2*this.prms.h1.v + this.prms.W.v)/3) { // Partially submerged only for orifices + this.debug("Structure.getFlowRegime(h1="+this.prms.h1.v+",h2="+this.prms.h2.v+",W="+this.prms.W.v+")=PARTIAL"); return StructureFlowRegime.PARTIAL; } else { // (Totally) submerged for both weirs and orifices + this.debug("Structure.getFlowRegime(h1="+this.prms.h1.v+",h2="+this.prms.h2.v+",W="+this.prms.W.v+")=SUBMERGED"); return StructureFlowRegime.SUBMERGED; } } @@ -170,4 +179,20 @@ export abstract class Structure extends Nub { if(sVarCalc!="Q") throw 'Structure.Equation() : invalid parameter name ' + sVarCalc; } + /** + * Calcul du mode et du régime d'écoulement + */ + Equation(sVarCalc: string): Result { + this.CheckEquation(sVarCalc); + let res: Result = new Result( + undefined, + undefined, + { + "Regime": this.getFlowRegime(), + "Mode": this.getFlowMode() + } + ); + return res; + } + } \ No newline at end of file diff --git a/src/structure/structure_cem88d.ts b/src/structure/structure_cem88d.ts index 324c7fac..706f9bd6 100644 --- a/src/structure/structure_cem88d.ts +++ b/src/structure/structure_cem88d.ts @@ -9,31 +9,41 @@ export { RectangularStructureParams }; export class StructureCem88d extends RectangularStructure { Equation(sVarCalc: string): Result { - this.CheckEquation(sVarCalc); + let res: Result = super.Equation(sVarCalc); let v : number; let cd : number = this.prms.Cd.v * this.prms.L.v * Structure.R2G; let b1 : number = Math.sqrt(this.prms.h1.v); - let b2 : number = Math.sqrt(this.prms.h2.v); - let cd1 : number = cd * 2.5981; - switch(this.getFlowMode()) { + let b2 : number = Math.sqrt(this.prms.h1.v-this.prms.h2.v); + let cd1 : number = cd * 2.5981; // cd * 3*sqrt(3)/2 + this.debug("StructureCem88d.Equation b1="+b1+" b2="+b2+" cd1="+cd1); + switch(res.extraVar['Mode']) { case StructureFlowMode.WEIR: - switch(this.getFlowRegime()) { + switch(res.extraVar['Regime']) { case StructureFlowRegime.FREE: v = cd * this.prms.h1.v * b1; + break; case StructureFlowRegime.SUBMERGED: - v = cd1 * this.prms.h1.v * b2; + v = cd1 * this.prms.h2.v * b2; + this.debug("StructureCem88d.Equation WEIR SUBMERGED Q="+v); + break; } + break; case StructureFlowMode.ORIFICE: - let b3 : number = this.prms.h1.v - this.prms.W.v; - switch(this.getFlowRegime()) { + let b3 : number = Math.pow(this.prms.h1.v - this.prms.W.v, 1.5); + switch(res.extraVar['Regime']) { case StructureFlowRegime.FREE: v = cd * (this.prms.h1.v * b1 -b3); + break; case StructureFlowRegime.PARTIAL: v = cd1 * b2 * this.prms.h2.v - cd * b3; + break; case StructureFlowRegime.SUBMERGED: v = cd1 * b2 * this.prms.W.v; + this.debug("StructureCem88d.Equation ORIFICE SUBMERGED Q="+v); + break; } } + this.debug("StructureCem88d.Equation(h1="+this.prms.h1.v+",h2="+this.prms.h2.v+",W="+this.prms.W.v+") => Q="+v); return new Result(v); } } -- GitLab