diff --git a/spec/structure/parallel_structure.spec.ts b/spec/structure/parallel_structure.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4601e2dbbf1b0e6365f7022606fc855dac857cf --- /dev/null +++ b/spec/structure/parallel_structure.spec.ts @@ -0,0 +1,39 @@ +/** + * IMPORTANT ! + * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine") + * Pour exécuter ce code dans le débugger. + * Faire de même avec le fichier test_func.ts + */ +// import { describe, expect, it, xdescribe } from "../mock_jasmine"; + +import { ParallelStructure } from "../../src/structure/parallel_structure"; +import { ParallelStructureParams } from "../../src/structure/parallel_structure_params"; +import { Result } from "../../src/util/result"; +import { checkResult } from "../test_func"; +import { structTest } from "./structure_test"; + +const pstruct: ParallelStructure = new ParallelStructure( + new ParallelStructureParams(30, 30, 15), // Q = 30, Z1 = 30, Z2 = 15 + false // debug +); + +// Test avec deux structures test identiques +pstruct.addStructure(structTest); +pstruct.addStructure(structTest); + +describe("Class ParallelStructure: ", () => { + describe("Calc()", () => { + itParallelStructure("Q", 30, 15); + itParallelStructure("Z1", 30, 15); + itParallelStructure("Z2", 15, 15); + }); +}); + +function itParallelStructure(sVarCalc: string, rVcalc: number, Q: number) { + it(`${sVarCalc} should be ${rVcalc}`, () => { + const res: Result = pstruct.Calc(sVarCalc); + checkResult(res, rVcalc); + checkResult(res.extractResult(1), Q); + checkResult(res.extractResult(2), Q); + }); +} diff --git a/spec/structure/structure.spec.ts b/spec/structure/structure.spec.ts index 77ae245395b81eba25dbf19109258b5bd054c1db..f1c23d0a8339db96b1e55bcffe6c0f9ee313de5e 100644 --- a/spec/structure/structure.spec.ts +++ b/spec/structure/structure.spec.ts @@ -47,7 +47,7 @@ describe("Class Structure: ", () => { describe("Calc()", () => { const flagsNull = { Mode: StructureFlowMode.NULL, Regime: StructureFlowRegime.NULL }; - it("h1=h2 => Q=0", () => { + it("Z1=Z2 => Q=0", () => { structTest.prms.Z2.v = structTest.prms.Z1.v; checkResult(structTest.Calc("Q"), 0); expect(structTest.Calc("Q").extraResults).toEqual(flagsNull); @@ -59,10 +59,10 @@ describe("Class Structure: ", () => { expect(structTest.Calc("Q").extraResults).toEqual(flagsNull); structTest.prms.W.v = Infinity; }); - it("Q=0 => h1=h2", () => { + it("Q=0 => Z1=Z2", () => { structTest.prms.Q.v = 0; - checkResult(structTest.Calc("h1"), structTest.prms.h2.v); - expect(structTest.Calc("h1").extraResults).toEqual(flagsNull); + checkResult(structTest.Calc("Z1"), structTest.prms.h2.v); + expect(structTest.Calc("Z1").extraResults).toEqual(flagsNull); structTest.prms.Q.v = 1; }); it("Q=0 => W=0", () => { diff --git a/spec/structure/structure_test.ts b/spec/structure/structure_test.ts index 20c03c7663255b53f70228fc0ce10965027d3cae..c4e582feafa5f8011717b2fe3b84eec917649034 100644 --- a/spec/structure/structure_test.ts +++ b/spec/structure/structure_test.ts @@ -26,10 +26,18 @@ class StructureTest extends Structure { public Equation(sVarCalc: string): Result { this.prms.update_h1h2(); Structure.CheckEquation(sVarCalc); - return new Result(this.prms.Z1.v - this.prms.Z2.v); + const data = this.getResultData(); + + return new Result(this.prms.Z1.v - this.prms.Z2.v, data); } } +/* Test structure with : + * - ZDV = 0 + * - Z1 = 30 + * - Z2 = 15 + * - expected Q = 15 + */ export const structTestPrm: StructureParams = new StructureParams(1, 0, 30, 15); export const structTest: StructureTest = new StructureTest(structTestPrm, false); diff --git a/src/structure/parallel_structure.ts b/src/structure/parallel_structure.ts new file mode 100644 index 0000000000000000000000000000000000000000..c692fd4b67dc9d68cd7efa14ad3ad1f69bb20e12 --- /dev/null +++ b/src/structure/parallel_structure.ts @@ -0,0 +1,152 @@ +import { Nub } from "../nub"; +import { ParamCalculability } from "../param"; +import { Message } from "../util/message"; +import { Result } from "../util/result"; +import { Structure } from "./structure"; + +import { ParallelStructureParams } from "./parallel_structure_params"; + +/** + * Calcul de une ou plusieurs structures hydrauliques en parallèles + * reliées par les cotes amont et aval et dont le débit est égal à la + * somme des débits de chaque structure. + */ +export class ParallelStructure extends Nub { + + /** Tableau des structures hydrauliques en parallèle */ + public structures: Structure[] = []; + + /** + * paramètres castés au bon type + */ + get prms(): ParallelStructureParams { + return this._prms as ParallelStructureParams; + } + + /** + * Mise à jour de Z1 pour toutes les structures en parallèle + */ + set Z1(Z1: number) { + this.prms.Z1.v = Z1; + for (const structure of this.structures) { + structure.prms.Z1.v = Z1; + structure.prms.update_h1h2(); + } + } + + /** + * Mise à jour de Z2 pour toutes les structures en parallèle + */ + set Z2(Z2: number) { + this.prms.Z2.v = Z2; + for (const structure of this.structures) { + structure.prms.Z2.v = Z2; + structure.prms.update_h1h2(); + } + } + + /** + * Ajout d'une structure en parallèle + * @param structure La structure à rajouter + */ + public addStructure(structure: Structure) { + this.structures.push(structure); + } + + /** + * Supprime une structure hydraulique + * @param index numéro de la structure dans le tableau + */ + public deleteStructure(index: number) { + if (index > -1) { + this.structures.splice(index, 1); + } else { + throw new Error("ParallelStructure.deleteStructure invalid index=" + index); + } + } + + /** + * Calcul du débit des structures en parallèle (sans détail pour chaque structure) + * @param sVarCalc Variable à calculer (Q uniquement) + */ + public Equation(sVarCalc: string): Result { + Structure.CheckEquation(sVarCalc); + this.Z1 = this.prms.Z1.v; + this.Z2 = this.prms.Z2.v; + return this.CalcQ(); + } + + /** + * Calcul de la somme des débits de chaque structure + * @param iExcept Index de la structure à ne pas additionner (optionel) + */ + public CalcQ(iExcept?: number): Result { + if (iExcept !== undefined) { + if (iExcept < 0 || iExcept >= this.structures.length) { + throw new Error( + "ParallelStructure.CalcQ iExcept not in [0;" + (this.structures.length - 1) + "]", + ); + } + } + const calcRes: Result = new Result(); + let qTot: number = 0; + for (let i = 0 ; i < this.structures.length; i++) { + if (i !== iExcept) { + const res: Result = this.structures[i].Calc("Q"); + calcRes.addResult(res.result); + qTot += res.vCalc; + } + } + // Insert le débit total en premier résultat + calcRes.insertResult(new Result(qTot).result, 0); + return calcRes; + } + + /** + * 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 = 0, rPrec: number = 0.001): Result { + switch (sVarCalc) { + case "Z1" : + case "Z2" : + case "Q" : + return super.Calc(sVarCalc, rInit, rPrec); + default: + // Pour les caractéristiques des ouvrages + return this.CalcStructPrm(sVarCalc, rInit, rPrec); + } + } + + /** + * paramétrage de la calculabilité des paramètres + */ + protected setParametersCalculability() { + this.prms.Q.calculability = ParamCalculability.EQUATION; + this.prms.Z1.calculability = ParamCalculability.DICHO; + this.prms.Z2.calculability = ParamCalculability.DICHO; + } + + /** + * Calcul du paramètre d'un des ouvrages en parallèle + * @param sVarCalc Nom du paramètre à calculer : "n.X" avec "n" l'index de l'ouvrage et "X" son paramètre + * @param rInit Valeur initiale + * @param rPrec Précision attendue + */ + private CalcStructPrm(sVarCalc: string, rInit: number = 0, rPrec: number = 0.001): Result { + // Détection de la structure où calculer le paramètre + let sIndex: string; + let sPrm: string; + [sIndex, sPrm] = sVarCalc.split("."); + const index = parseInt(sIndex, 10); + + // Le débit restant sur la structure en calcul est : + const qTarget: number = this.prms.Q.v - this.CalcQ(index).vCalc; + + // Calcul du paramètre de la structure en calcul + return this.structures[index].Calc(sPrm, rInit, rPrec); + } +} diff --git a/src/structure/parallel_structure_params.ts b/src/structure/parallel_structure_params.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7d556dbfc0eb1b920e3da8ea900491eecd8023c --- /dev/null +++ b/src/structure/parallel_structure_params.ts @@ -0,0 +1,32 @@ +import { Nub } from "../nub"; +import { ComputeNodeType, ParamDefinition, ParamDomainValue, ParamsEquation } from "../param"; + +/** + * Common parameters of hydraulic structure equations + */ +export class ParallelStructureParams extends ParamsEquation { + /** Débit (m3/s) */ + public Q: ParamDefinition; + + /** Cote de l'eau amont (m) */ + public Z1: ParamDefinition; + + /** Cote de l'eau aval (m) */ + public Z2: ParamDefinition; + + /** + * Paramètres communs à toutes les équations de structure + * @param rQ Débit total (m3/s) + * @param rZ1 Cote de l'eau amont (m) + * @param rZ2 Cote de l'eau aval (m) + */ + constructor(rQ: number, rZ1: number, rZ2: number) { + super(); + this.Q = new ParamDefinition(ComputeNodeType.CondDistri, "Q", ParamDomainValue.ANY, rQ); + this.addParamDefinition(this.Q); + this.Z1 = new ParamDefinition(ComputeNodeType.CondDistri, "Z1", ParamDomainValue.ANY, rZ1); + this.addParamDefinition(this.Z1); + this.Z2 = new ParamDefinition(ComputeNodeType.CondDistri, "Z2", ParamDomainValue.ANY, rZ2); + this.addParamDefinition(this.Z2); + } +} diff --git a/src/structure/structure.ts b/src/structure/structure.ts index ca8abac0fe2b525da10664807698c6d4ce630407..809ab19b02c5645c081e3dbec810d14c14b6260f 100644 --- a/src/structure/structure.ts +++ b/src/structure/structure.ts @@ -11,12 +11,12 @@ export { StructureParams }; * Flow mode: weir or orifice flow */ export enum StructureFlowMode { - /** Weir flow */ - WEIR, - /** Orifice flow */ - ORIFICE, - /** Zéro flow */ - NULL, + /** Weir flow */ + WEIR, + /** Orifice flow */ + ORIFICE, + /** Zéro flow */ + NULL, } /** @@ -31,7 +31,7 @@ export enum StructureFlowRegime { SUBMERGED, /** Zéro flow */ NULL, - } +} /** * classe de calcul sur la conduite distributrice @@ -79,23 +79,42 @@ export abstract class Structure extends Nub { } else if (this.prms.Q.v === 0) { // Débit nul <=> tirant d'eau amont = tirant d'eau aval ou tout autre paramètre nul switch (sVarCalc) { - case "h1" : - return new Result(this.prms.h2.v, flagsNull); - case "h2" : - return new Result(this.prms.h1.v, flagsNull); + case "Z1" : + return new Result(this.prms.h2.v, flagsNull); + case "Z2" : + return new Result(this.prms.h1.v, flagsNull); default : - // Est-ce toujours vrai ? Nécessitera peut-être d'étendre la méthode - return new Result(0, flagsNull); + // Est-ce toujours vrai ? Nécessitera peut-être d'étendre la méthode + return new Result(0, flagsNull); } - } else if (this.prms.W.v === 0 && sVarCalc === "h1") { + } else if (this.prms.W.v === 0 && sVarCalc === "Z1") { return new Result(Infinity, flagsNull); // Si la vanne est fermée la cote amont est infinie } + // Gestion du cas d'écoulement impossible Z1 > Z2 et Q <= 0 + if (!(sVarCalc === "Q" || sVarCalc === "Z1" || sVarCalc === "Z2")) { + if ( + (this.prms.Z1.v > this.prms.Z2.v && this.prms.Q.v <= 0) || + (this.prms.Z1.v < this.prms.Z2.v && this.prms.Q.v >= 0) + ) { + // On ferme l'ouvrage et on renvoie un code d'erreur + let rPrm: number; + switch (sVarCalc) { + case "ZDV": + rPrm = Infinity; + default: + rPrm = 0; + } + // TODO Ajouter un message d'erreur + // "Les cotes et le débit ne sont pas cohérents => fermeture de l'ouvrage + return new Result(rPrm, flagsNull); + } + } + // Gestion de l'inversion de débit : on inverse l'amont et l'aval pour le calcul if ((sVarCalc === "Q" && (this.prms.h1.v < this.prms.h2.v)) || (sVarCalc !== "Q" && this.prms.Q.v < 0)) { [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion - let res: Result; - res = super.Calc(sVarCalc, rInit, rPrec); + const res: Result = super.Calc(sVarCalc, rInit, rPrec); [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion return res; } @@ -104,7 +123,7 @@ export abstract class Structure extends Nub { return super.Calc(sVarCalc, rInit, rPrec); } - protected defaultResultData() { + protected getResultData() { return { Mode: this.getFlowMode(), Regime: this.getFlowRegime(), diff --git a/src/structure/structure_cem88d.ts b/src/structure/structure_cem88d.ts index 99c675de829c5c94b934cda2a0bc92d775c66738..27c2405d7bc35b16eb5633bcd088feac5ea74d3d 100644 --- a/src/structure/structure_cem88d.ts +++ b/src/structure/structure_cem88d.ts @@ -16,7 +16,7 @@ export class StructureCem88d extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); let v: number; const cd: number = this.prms.Cd.v * this.prms.L.v * Structure.R2G; diff --git a/src/structure/structure_cem88v.ts b/src/structure/structure_cem88v.ts index b636fc0e55dd51ded8f86bf7309ce63c8bd21d05..c0dc94caaaef79047b945e1fd85517529441c697 100644 --- a/src/structure/structure_cem88v.ts +++ b/src/structure/structure_cem88v.ts @@ -16,7 +16,7 @@ export class StructureCem88v extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); let v: number; const mu0: number = 2 / 3 * this.prms.Cd.v; diff --git a/src/structure/structure_cunge80.ts b/src/structure/structure_cunge80.ts index 38435d5546636ebdebaac7249e4cda28d4d3ed0d..155aa52ccefcc731842e9645cc77b26d3ffe6060 100644 --- a/src/structure/structure_cunge80.ts +++ b/src/structure/structure_cunge80.ts @@ -15,7 +15,7 @@ export class StructureCunge80 extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); let v: number; switch (data.Regime) { diff --git a/src/structure/structure_orifice_free.ts b/src/structure/structure_orifice_free.ts index 1f4b266fc2a665fd1a18a7e6b8b7c25b6946f002..4d18544dcf38ff1823b7a8b9f9b2856bec36a744 100644 --- a/src/structure/structure_orifice_free.ts +++ b/src/structure/structure_orifice_free.ts @@ -15,13 +15,15 @@ export class StructureOrificeFree extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); - // TODO : Warning si les conditions hydrauliques ne correspondent pas à un écoulement dénoyé - data.Regime = StructureFlowRegime.FREE; const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v * Structure.R2G * Math.sqrt(this.prms.h1.v); return new Result(v, data); } + + protected getFlowRegime() { + return StructureFlowRegime.FREE; + } } diff --git a/src/structure/structure_orifice_submerged.ts b/src/structure/structure_orifice_submerged.ts index c4f42b50dc793947217a0873660bb901d0fa629e..dd91446e475f119e28d99423f07863ba4d8662df 100644 --- a/src/structure/structure_orifice_submerged.ts +++ b/src/structure/structure_orifice_submerged.ts @@ -15,13 +15,15 @@ export class StructureOrificeSubmerged extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); - // TODO : Warning si les conditions hydrauliques ne correspondent pas à un écoulement dénoyé - data.Regime = StructureFlowRegime.SUBMERGED; const v = this.prms.Cd.v * Math.min(this.prms.W.v, this.prms.h1.v) * this.prms.L.v * Structure.R2G * Math.sqrt(this.prms.h1.v - this.prms.h2.v); return new Result(v, data); } + + protected getFlowRegime() { + return StructureFlowRegime.SUBMERGED; + } } diff --git a/src/structure/structure_weir_free.ts b/src/structure/structure_weir_free.ts index 57ff2f154d8911268d1125ac6854c6565a413278..444dc37259efab1ba4d2a4305cc5b7273ce756f0 100644 --- a/src/structure/structure_weir_free.ts +++ b/src/structure/structure_weir_free.ts @@ -15,13 +15,18 @@ export class StructureWeirFree extends RectangularStructure { */ public Equation(sVarCalc: string): Result { Structure.CheckEquation(sVarCalc); - const data = super.defaultResultData(); + const data = this.getResultData(); - // TODO : Warning si les conditions hydrauliques ne correspondent pas à un seuil dénoyé - data.Regime = StructureFlowRegime.FREE; - data.Mode = StructureFlowMode.WEIR; const v = this.prms.Cd.v * this.prms.L.v * Structure.R2G * Math.pow(this.prms.h1.v, 1.5); return new Result(v, data); } + + protected getFlowRegime() { + return StructureFlowRegime.FREE; + } + + protected getFlowMode() { + return StructureFlowMode.WEIR; + } }