diff --git a/spec/macrorugo/macrorugo.spec.ts b/spec/macrorugo/macrorugo.spec.ts index 882c2d461d98ed1dccca593264618932a2295319..3f1de14c2a0e5f34a5b48652d5d7d42ecc820761 100644 --- a/spec/macrorugo/macrorugo.spec.ts +++ b/spec/macrorugo/macrorugo.spec.ts @@ -6,7 +6,7 @@ */ // import { describe, expect, it, xdescribe, xit } from "../mock_jasmine"; -import { ParamCalculability } from "../../src"; +import { ParamCalculability, ParamValueMode } from "../../src"; import { MacroRugo, MacrorugoParams } from "../../src/macrorugo/macrorugo"; import { checkResult } from "../test_func"; @@ -17,7 +17,7 @@ function macroRugoInstance(): MacroRugo { 6, // L 1, // B 0.05, // If - 0.5, // Q + 9.418, // Q 0.6, // h 0.01, // Ks 0.05, // C @@ -28,15 +28,15 @@ function macroRugoInstance(): MacroRugo { ); } -function testMacroRugo(varTest: string) { +function testMacroRugo(varTest: string, valRef: number) { describe("Calc(): ", () => { - it("V should be 1", () => { + it(`${varTest} should be ${valRef}`, () => { const nub = macroRugoInstance(); nub.prms.Q.v = nub.Calc("Q").vCalc; - const res: number = nub.prms[varTest].v; - nub.prms[varTest].v = undefined; - - checkResult(nub.Calc(varTest, 0), res); + const p = nub.getParameter(varTest); + p.v = undefined; + p.valueMode = ParamValueMode.CALCUL; + checkResult(nub.Calc(varTest, 0.1), valRef); }); }); } @@ -48,7 +48,7 @@ describe("Class MacroRugo: ", () => { for (const prm of nub.prms) { if ([ParamCalculability.DICHO, ParamCalculability.EQUATION].includes(prm.calculability)) { - testMacroRugo(prm.symbol); + testMacroRugo(prm.symbol, prm.v); } } }); diff --git a/spec/test_func.ts b/spec/test_func.ts index aa4d012028838d680790c2a47e98c47138279e09..742cd8802a24196ca55f238dbc269ee881bb842e 100644 --- a/spec/test_func.ts +++ b/spec/test_func.ts @@ -184,7 +184,7 @@ export function compareLog(logTest: cLog, logValid: cLog) { } export function checkResult(val1: Result, val2: number, prec?: number) { - expect(val1.ok).toBeTruthy("Result : computation error on Result " + val1.toString()); + expect(val1.ok).toBeTruthy((!val1.ok) ? "Result: ERROR code=" + MessageCode[val1.code] : ""); if (val1.ok) { /* * on demande une précision de vérification inférieure à la précision de calcul diff --git a/src/macrorugo/macrorugo.ts b/src/macrorugo/macrorugo.ts index 89571a76f87d4db4b7ff11ddb6f5378763a5304d..a6cf36d89c24de7c8631fe9d4fd52d278b1e8988 100644 --- a/src/macrorugo/macrorugo.ts +++ b/src/macrorugo/macrorugo.ts @@ -5,6 +5,12 @@ import { MacrorugoParams } from "./macrorugo_params"; export { MacrorugoParams }; +export enum MacroRugoFlowType { + EMERGENT, + QUASI_EMERGENT, + IMMERGE +} + export class MacroRugo extends Nub { private static readonly g = 9.81; @@ -16,6 +22,10 @@ export class MacroRugo extends Nub { /** Ratio between the lenght (parallel to flow) and the width (perpendicular to flow) of a cell (-) */ private static readonly fracAyAx = 1; + + /** Limit between emergent and submerged flow */ + private static readonly limitSubmerg = 1.1; + /** Rugosité de fond (m) */ private ks: number; /** Averaged velocity at the bed (m.s-1) */ @@ -34,17 +44,84 @@ export class MacroRugo extends Nub { return this._prms as MacrorugoParams; } + /** + * 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 : + * "Q", "Z1", "Z2" ou "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre + * @param rInit Valeur initiale + * @param rPrec Précision attendue + */ + public Calc(sVarCalc: string, rInit?: number, rPrec: number = 0.001): Result { + const r: Result = super.Calc(sVarCalc, rInit, rPrec); + // Ajout des résultats complémentaires + // Cote de fond aval + r.extraResults.ZF2 = this.prms.ZF1.v - this.prms.If.v * this.prms.L.v; + // Vitesse débitante + r.extraResults.Vdeb = this.V(this.prms.Q) / this.prms.B.v / this.prms.Y.v; + // Vitesse maximale + r.extraResults.V = r.extraResults.Vdeb * this.calc_fFr(r.extraResults.Vdeb); + // Puissance dissipée + r.extraResults.P = 1000 * MacroRugo.g * this.V(this.prms.Q) / this.prms.B.v * this.prms.If.v; + // Type d'écoulement + if (this.prms.Y.v / this.prms.PBH.v < 1) { + r.extraResults.FlowType = MacroRugoFlowType.EMERGENT; + } else if (this.prms.Y.v / this.prms.PBH.v < 1.1) { + r.extraResults.FlowType = MacroRugoFlowType.QUASI_EMERGENT; + } else { + r.extraResults.FlowType = MacroRugoFlowType.IMMERGE; + } + // Vitesse et débit du guide technique + let cQ: [number, number, number, number]; + let cV: [number, number, number]; + if (this.prms.Y.v / this.prms.PBH.v > 1.1) { + cQ = [0.955, 2.282, 0.466, -0.23]; + } else { + if (Math.abs(this.prms.Cd0.v - 2) < 0.05) { + cQ = [0.648, 1.084, 0.56, -0.456]; + cV = [3.35, 0.27, 0.53]; + } else { + cQ = [0.815, 1.45, 0.557, -0.456]; + cV = [4.54, 0.32, 0.56] + } + } + r.extraResults.Q2 = cQ[0] * Math.pow(this.prms.Y.v / this.prms.PBH.v, cQ[1]) * + Math.pow(this.prms.If.v, cQ[2]) * Math.pow(this.prms.C.v, cQ[3]) * + Math.sqrt(MacroRugo.g * this.prms.PBD.v) * this.prms.PBH.v * this.prms.B.v; + if (this.prms.Y.v / this.prms.PBH.v <= 1.1) { + r.extraResults.V2 = cV[0] * Math.pow(this.prms.Y.v / this.prms.PBD.v, cV[1]) * + Math.pow(this.prms.If.v, cQ[2]) * Math.sqrt(MacroRugo.g * this.prms.PBD.v); + } + return r; + } + public Equation(sVarCalc: string): Result { - const Q = uniroot(this.calcQ, this, 0, 1E7); + const Q = uniroot(this.calcQ, this, 0, 1E7) * this.prms.B.v; return new Result(Q); } + /** + * paramétrage de la calculabilité des paramètres + */ + protected setParametersCalculability() { + this.prms.ZF1.calculability = ParamCalculability.FREE; + this.prms.L.calculability = ParamCalculability.FREE; + this.prms.Ks.calculability = ParamCalculability.FREE; + this.prms.B.calculability = ParamCalculability.DICHO; + this.prms.If.calculability = ParamCalculability.DICHO; + this.prms.Q.calculability = ParamCalculability.EQUATION; + this.prms.Y.calculability = ParamCalculability.DICHO; + this.prms.C.calculability = ParamCalculability.DICHO; + this.prms.PBD.calculability = ParamCalculability.DICHO; + this.prms.PBH.calculability = ParamCalculability.FREE; + this.prms.Cd0.calculability = ParamCalculability.DICHO; + } + /** * Equation from Cassan, L., Laurens, P., 2016. Design of emergent and submerged rock-ramp fish passes. * Knowledge & Management of Aquatic Ecosystems 45. * @param sVarCalc Variable à calculer */ - public calcQ(this: MacroRugo, Q: number): number { + private calcQ(this: MacroRugo, Q: number): number { // Reset cached variables depending on Q (or not...) this._cache = {}; /** Longueur (m) */ @@ -69,13 +146,17 @@ export class MacroRugo extends Nub { const g = MacroRugo.g; const kappa = 0.41; // von Karman constant + // u0 = Averaged velocity at the bed (m.s-1) + this.u0 = Q / this.prms.L.v / this.prms.Y.v; + /** Calulated average velocity */ let u: number; - if (h / k > 1.1) { + if (h / k > MacroRugo.limitSubmerg) { // Submerged conditions /** Velocity at the bed §2.3.2 Cassan et al., 2016 */ - this.u0 = Math.sqrt(2 * g * S * D * this.R / (Cd0 * C)); + /** @todo Faut-il un point fixe ici vu que Cd dépend de u0 ? */ + this.u0 = Math.sqrt(2 * g * S * D * this.R / (this.calcCd(this.calc_fFr(this.u0)) * C)); /** turbulent length scale (m) within the blocks layer (alpha_t) */ const alpha = uniroot(this.calcAlpha_t, this, 0, 100); /** averaged velocity at the top of blocks (m.s-1) */ @@ -110,11 +191,8 @@ export class MacroRugo extends Nub { } else { // Emergent conditions - // u0 = Averaged velocity at the bed (m.s-1) - this.u0 = Q / this.prms.L.v / this.prms.Y.v; - // Resolve equation (4) Cassan et al., 2016 - u = uniroot(this.calcU0, this, 0, 1E7); + u = uniroot(this.resolveU0, this, 0, 1E7); } return this.u0 - u; } @@ -144,16 +222,16 @@ export class MacroRugo extends Nub { if (this._cache.R !== undefined) { return this._cache.R; } - return (1 - this.sigma * this.prms.C.v) * Math.pow(1 - Math.sqrt(this.prms.C.v), 2); + return (1 - this.sigma * this.prms.C.v); } /** * Bed friction coefficient Equation (3) (Cassan et al., 2016) */ - private get Cf(): number { + private calcCf(U0: number): number { // Between Eq (8) and (9) (Cassan et al., 2016) // tslint:disable-next-line:variable-name - const Re = this.u0 * this.prms.Y.v / MacroRugo.nu; + const Re = U0 * this.prms.Y.v / MacroRugo.nu; if (this.prms.Ks.v < 1E-6) { return 0.3164 / 4. * Math.pow(Re, -0.25); @@ -163,23 +241,6 @@ export class MacroRugo extends Nub { } } - /** - * paramétrage de la calculabilité des paramètres - */ - protected setParametersCalculability() { - this.prms.ZF1.calculability = ParamCalculability.FREE; - this.prms.L.calculability = ParamCalculability.FREE; - this.prms.Ks.calculability = ParamCalculability.FREE; - this.prms.B.calculability = ParamCalculability.DICHO; - this.prms.If.calculability = ParamCalculability.DICHO; - this.prms.Q.calculability = ParamCalculability.EQUATION; - this.prms.Y.calculability = ParamCalculability.DICHO; - this.prms.C.calculability = ParamCalculability.DICHO; - this.prms.PBD.calculability = ParamCalculability.FREE; - this.prms.PBH.calculability = ParamCalculability.FREE; - this.prms.Cd0.calculability = ParamCalculability.FREE; - } - /** * Calculation of Cd : drag coefficient of a block under the actual flow conditions * @param Cd0 @@ -230,17 +291,17 @@ export class MacroRugo extends Nub { return alpha * this.calcUz(alpha) - l0 * this.ustar; } - private calcU0(U01: number) { + private resolveU0(U0: number) { const g = MacroRugo.g; const alpha = 1 - (1 * this.prms.C.v); // tslint:disable-next-line:variable-name - const Cd = this.calcCd(this.calc_fFr(U01)); + const Cd = this.calcCd(this.calc_fFr(U0)); /** N from Cassan 2016 eq(2) et Cassan 2014 eq(12) */ - const N = (alpha * this.Cf) / (this.prms.Y.v / this.prms.PBD.v * Cd * this.prms.C.v); + const N = (alpha * this.calcCf(U0)) / (this.prms.Y.v / this.prms.PBD.v * Cd * this.prms.C.v); - return U01 - Math.sqrt( + return U0 - Math.sqrt( 2 * MacroRugo.g * this.prms.If.v * this.prms.PBD.v * (1 - this.sigma * this.prms.C.v) / (Cd * this.prms.C.v * (1 + N)) ); diff --git a/src/nub.ts b/src/nub.ts index 99e2c66a4b7016ba2870259cca89a9b92d5f34ab..eec9c95409cabc63bffe5a0208b5105261ae7ea0 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -110,8 +110,9 @@ export abstract class Nub extends ComputeNode implements IReferencedNub { case ParamValueMode.LINK: const ro = p.referencedObject; - if (ro !== undefined && ro.hasMultipleValues) + if (ro !== undefined && ro.hasMultipleValues) { variatedValues = this.setVariatedValues(p, variatedValues); + } break; default: @@ -161,6 +162,22 @@ export abstract class Nub extends ComputeNode implements IReferencedNub { return this._result; } + /** + * Renvoie la valeur actuelle d'un paramètre (valeur utilisateur ou résultat) + * @param p Paramètre + */ + public V(p: ParamDefinition): number { + if (p.valueMode === ParamValueMode.CALCUL) { + if (this.result !== undefined) { + if (this.result.ok) { + return this.result.vCalc; + } + } + throw new Error(`Attempt to read the result of ${p.symbol} but none found`); + } + return p.v; + } + // interface IReferencedNub public getReferencedParamValues(desc: string): ParamValues { @@ -218,7 +235,7 @@ export abstract class Nub extends ComputeNode implements IReferencedNub { * correspondant à la clé de recherche * @returns tableau d'objets de la forme { "name":string, "value":NamedIterableValues, "nub":Nub}, * nub=Nub d'origine de la "value" - * + * * l'étiquette "name" (cf. INubReference.defineReference) est de la forme <n | ouvrage[n] | N1>[.[N2]] * n : indice de de l'ouvrage dans le cas des ouvrages parallèles * N1 : un nom de paramètre/résultat (dans le cas d'un résultat, il est suivi d'un point)