From ec287517647c3eb8279cb3afd17b076287fce2ee Mon Sep 17 00:00:00 2001
From: David Dorchies <david.dorchies@irstea.fr>
Date: Mon, 6 Nov 2017 12:24:32 +0100
Subject: [PATCH] =?UTF-8?q?#6=20Cr=C3=A9ation=20de=20la=20classe=20de=20ba?=
 =?UTF-8?q?se=20des=20ouvrages?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 spec/structure/structure.spec.ts | 118 +++++++++++++++++++++++
 src/structure/structure.ts       | 156 +++++++++++++++++++++++++++++++
 2 files changed, 274 insertions(+)
 create mode 100644 spec/structure/structure.spec.ts
 create mode 100644 src/structure/structure.ts

diff --git a/spec/structure/structure.spec.ts b/spec/structure/structure.spec.ts
new file mode 100644
index 00000000..ea18f087
--- /dev/null
+++ b/spec/structure/structure.spec.ts
@@ -0,0 +1,118 @@
+/// <reference path="../../node_modules/@types/jasmine/index.d.ts" />
+
+import { Structure, StructureParams, StructureFlowMode, StructureFlowRegime} from "../../src/structure/structure";
+import { Result } from "../../src/base";
+import { equalEpsilon } from "../nubtest";
+
+function check(val1: Result, val2: number) {
+    expect(equalEpsilon(val1.vCalc, val2)).toBe(true);
+}
+
+
+class StructureTestParams extends StructureParams {
+
+}
+
+
+class StructureTest extends Structure {
+
+    constructor(prms: StructureTestParams, dbg: boolean = false) {
+        super(prms, dbg);
+        this.setParametersCalculability();
+    }
+
+    Equation(sVarCalc: string): Result {
+        let res: Result;
+        let v: number;
+        
+        switch (sVarCalc) {
+            case "Q":
+                v = this.prms.h1.v-this.prms.h2.v;
+                break;
+                default:
+                throw 'StructureTest.Equation() : invalid parameter name ' + sVarCalc;
+        }
+
+        return res;
+    }
+
+    /**
+     * Test of getFlowMode
+     */
+    public testGetFlowMode() {
+        return this.getFlowMode();
+    }
+
+    /**
+     * Test of getFlowRegime
+     */
+    public testGetFlowRegime() {
+        return this.getFlowRegime();
+    }
+
+}
+
+
+let structTestPrm: StructureParams = new StructureTestParams(1, 30, 15);
+let structTest: StructureTest = new StructureTest(structTestPrm, true);
+
+
+describe('Class Structure: ', () => {
+
+    describe('getFlowMode()', () => {
+        it('Flow Mode should be WEIR', () => {
+            expect(structTest.testGetFlowMode()).toBe(StructureFlowMode.WEIR);
+        });    
+        it('Flow Mode should be ORIFICE', () => {
+            structTest.prms.W.v = 10;
+            expect(structTest.testGetFlowMode()).toBe(StructureFlowMode.ORIFICE);
+            structTest.prms.W.v = Infinity;
+        }); 
+    });
+
+    describe('getFlowRegime()', () => {
+        it('Flow Regime should be FREE', () => {
+            expect(structTest.testGetFlowRegime()).toBe(StructureFlowRegime.FREE);
+        });    
+        it('Flow Regime should be SUBMERGED (WEIR)', () => {            
+            structTest.prms.h2.v = 21;
+            expect(structTest.testGetFlowRegime()).toBe(StructureFlowRegime.SUBMERGED);
+        });
+        it('Flow Regime should be PARTIAL (ORIFICE)', () => {            
+            structTest.prms.h2.v = 21;
+            structTest.prms.W.v = 15;
+            expect(structTest.testGetFlowRegime()).toBe(StructureFlowRegime.PARTIAL);
+        });
+        it('Flow Regime should be SUBMERGED (ORIFICE)', () => {            
+            structTest.prms.h2.v = 25;
+            structTest.prms.W.v = 15;
+            expect(structTest.testGetFlowRegime()).toBe(StructureFlowRegime.SUBMERGED);
+        });
+        structTest.prms.h2.v = 15;
+        structTest.prms.W.v = Infinity; 
+    });
+    describe('Calc()', () => {
+        it('h1=h2 => Q=0', () => {
+            structTest.prms.h2.v = structTest.prms.h1.v;
+            check(structTest.Calc('Q'),0);
+            structTest.prms.h2.v = 15;
+        });
+        it('W=0 => Q=0', () => {
+            structTest.prms.W.v = 0;
+            check(structTest.Calc('Q'),0);
+            structTest.prms.W.v = Infinity;
+        });
+        it('Q=0 => h1=h2', () => {
+            structTest.prms.Q.v = 0;
+            check(structTest.Calc('h1'),structTest.prms.h2.v);
+            structTest.prms.Q.v = 1;
+        });
+        it('Q=0 => W=0', () => {
+            structTest.prms.Q.v = 0;
+            check(structTest.Calc('W'),0);
+            structTest.prms.Q.v = 1;
+        });
+        // TODO Test inversion de débit
+
+    });
+});
\ No newline at end of file
diff --git a/src/structure/structure.ts b/src/structure/structure.ts
new file mode 100644
index 00000000..9b41135c
--- /dev/null
+++ b/src/structure/structure.ts
@@ -0,0 +1,156 @@
+/**
+ * @file structure/structure.ts Base classes for hydraulic structure equations
+ */
+import { Result } from "../base";
+import { ComputeNodeType, ParamDefinition, ParamDomain, ParamDomainValue, ParamCalculability, ParamsEquation } from "../param";
+import { Nub } from "../nub";
+
+
+/**
+ * Common parameters of hydraulic structure equations
+ */
+export abstract class StructureParams extends ParamsEquation {
+    /** Débit */
+    Q: ParamDefinition;
+
+    /** Tirant d'eau amont */
+    h1: ParamDefinition;
+
+    /** Tirant d'eau aval */
+    h2: ParamDefinition;
+
+    /** Ouverture de la vanne
+     * @note Pour un seuil cette valeur vaut Infinity
+     */
+    W: ParamDefinition;
+
+    constructor(rQ: number, rh1: number, rh2: number, rW: number = Infinity ) {
+        super();
+        this.Q = new ParamDefinition(ComputeNodeType.CondDistri, 'Q', ParamDomainValue.POS_NULL, rQ);
+        this.h1 = new ParamDefinition(ComputeNodeType.CondDistri, 'h1', ParamDomainValue.POS_NULL, rh1);
+        this.h2 = new ParamDefinition(ComputeNodeType.CondDistri, 'h2', ParamDomainValue.POS_NULL, rh2);
+        this.W = new ParamDefinition(ComputeNodeType.CondDistri, 'W', ParamDomainValue.POS_NULL, rW);
+    }
+}
+
+
+/**
+* Flow mode: weir or orifice flow
+*/
+export enum StructureFlowMode {
+   /** Weir flow */
+   WEIR,
+   /** Orifice flow */
+   ORIFICE
+}
+
+
+/**
+* Flow regime: free flow, partially submerged or submerged
+*/
+export enum StructureFlowRegime {
+    /** Free flow (unsubmerged) */
+    FREE,
+    /** Partially submerged flow */
+    PARTIAL, 
+    /** Submerged flow */
+    SUBMERGED
+ }
+ 
+
+/**
+ * classe de calcul sur la conduite distributrice
+ */
+export abstract class Structure extends Nub {
+    constructor(prms: StructureParams, dbg: boolean = false) {
+        super(prms, dbg);
+    }
+
+
+   /**
+     * paramètres castés au bon type
+     */
+    get prms(): StructureParams {
+        return <StructureParams>this._prms;
+    }
+
+
+    /**
+     * paramétrage de la calculabilité des paramètres
+     */
+    protected setParametersCalculability() {
+        this.prms.Q.calculability = ParamCalculability.EQUATION;
+        this.prms.h1.calculability = ParamCalculability.DICHO;
+        this.prms.h2.calculability = ParamCalculability.DICHO;
+        this.prms.W.calculability = ParamCalculability.DICHO;
+    }
+
+
+    /**
+     * 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; 
+    }
+
+
+    /**
+     * Give the flow regime for a rectangular section : free, partially submerged or submerged flow
+     */
+    protected getFlowRegime(): StructureFlowRegime  {
+        // Weir have only two flow regimes: free and submerged flow
+        // 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
+            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
+            return StructureFlowRegime.PARTIAL;
+        } else {
+            // (Totally) submerged for both weirs and orifices
+            return StructureFlowRegime.SUBMERGED;
+        }
+    }
+     
+
+    /** 
+     * Calcul d'une équation quelque soit l'inconnue à calculer.
+     * Gestion du débit nul et de l'inversion de débit
+     * @param sVarCalc nom de la variable à calculer
+     * @param rInit valeur initiale de la variable à calculer dans le cas de la dichotomie
+     * @param rPrec précision de calcul
+     */
+    Calc(sVarCalc: string, rInit: number = 0, rPrec: number = 0.001): Result {
+                
+        // Gestion du débit nul
+        if(sVarCalc == 'Q') {
+            if(this.prms.h1.v == this.prms.h2.v || this.prms.W.v <= 0) {
+                return new Result(0);
+            }
+        } 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);
+                case "h2" :
+                    return new Result(this.prms.h1.v);
+                default :
+                    return new Result(0); // Est-ce toujours vrai ? Nécessitera peut-être d'étendre la méthode
+            }
+        }
+
+        // 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);
+            [this.prms.h1.v, this.prms.h2.v] = [this.prms.h2.v, this.prms.h1.v]; // Swap ES6 fashion
+            return res;
+        }
+        
+        return super.Calc(sVarCalc, rInit, rPrec);
+        
+    }
+    
+}
\ No newline at end of file
-- 
GitLab