structure.ts 13 KB
Newer Older
Mathias Chouet's avatar
Mathias Chouet committed
1
import { CalculatorType } from "../compute-node";
2
import { Nub } from "../nub";
Mathias Chouet's avatar
Mathias Chouet committed
3
import { ParamCalculability, ParamDefinition } from "../param/param-definition";
Mathias Chouet's avatar
Mathias Chouet committed
4
import { Props } from "../props";
Dorchies David's avatar
Dorchies David committed
5
import { Message, MessageCode } from "../util/message";
6
import { Result } from "../util/result";
Mathias Chouet's avatar
Mathias Chouet committed
7
import { StructureParams } from "./structure_params";
Mathias Chouet's avatar
Mathias Chouet committed
8
import { LoiDebit } from "./structure_props";
9
10

/**
11
12
 * Flow mode: weir or orifice flow
 */
13
export enum StructureFlowMode {
14
15
16
17
18
    /** Weir flow */
    WEIR,
    /** Orifice flow */
    ORIFICE,
    /** Zéro flow */
19
    NULL
20
21
22
}

/**
23
24
 * Flow regime: free flow, partially submerged or submerged
 */
25
26
27
28
export enum StructureFlowRegime {
    /** Free flow (unsubmerged) */
    FREE,
    /** Partially submerged flow */
29
    PARTIAL,
30
    /** Submerged flow */
31
    SUBMERGED,
32
    /** Zéro flow */
33
    NULL
34
}
35

36
37
38
39
40
41
42
43
44
/**
 * Type de jet : Sans objet (orifice), plongeant, de surface
 */
export enum StructureJetType {
    /** Sans objet (orifice) */
    SO,
    /** Plongeant */
    PLONGEANT,
    /** De surface */
45
    SURFACE
46
47
}

48
49
50
51
/**
 * classe de calcul sur la conduite distributrice
 */
export abstract class Structure extends Nub {
52

53
54
55
56
57
58
59
    /**
     * Test générique si VarCalc="Q" pour l'utilisation de Equation
     */
    public static CheckEquation(sVarCalc: string) {
        if (sVarCalc !== "Q") { throw new Error("Structure.Equation() : invalid parameter name " + sVarCalc); }
    }

60
    /** Constante utile : Racine de 2g */
61
    protected static readonly R2G: number = Math.sqrt(2 * 9.81);
62

Dorchies David's avatar
Dorchies David committed
63
64
65
    /** Peut-on calculer ZDV ? */
    protected _isZDVcalculable: boolean;

Mathias Chouet's avatar
Mathias Chouet committed
66
67
    protected _loiDebit: LoiDebit;

68
69
    constructor(prms: StructureParams, dbg: boolean = false) {
        super(prms, dbg);
Mathias Chouet's avatar
Mathias Chouet committed
70
        this._calcType = CalculatorType.Structure;
Dorchies David's avatar
Dorchies David committed
71
        this._isZDVcalculable = true;
72
73
74
        // Q is always the only calculated variable; setting another parameter
        // of a Structure to CALC mode makes it the calculated variable of the
        // *parent* ParallelStructures
Mathias Chouet's avatar
Mathias Chouet committed
75
        this.calculatedParam = this.prms.Q;
Dorchies David's avatar
Dorchies David committed
76
77
    }

Mathias Chouet's avatar
Mathias Chouet committed
78
79
    /** Returns Props object (observable set of key-values) associated to this Nub */
    public get properties(): Props {
80
        // completes props with calcType and loiDebit if not already set
Mathias Chouet's avatar
Mathias Chouet committed
81
        this._props.setPropValue("calcType", this.calcType);
82
83
84
        if (this._props.getPropValue("loiDebit") === undefined) {
            this._props.setPropValue("loiDebit", this._loiDebit);
        }
Mathias Chouet's avatar
Mathias Chouet committed
85
86
87
88
89
        return this._props;
    }

    // setter is not inherited from Nub if getter is redefined :/
    public set properties(props: Props) {
Mathias Chouet's avatar
Mathias Chouet committed
90
        super.setProperties(props);
Mathias Chouet's avatar
Mathias Chouet committed
91
92
    }

Dorchies David's avatar
Dorchies David committed
93
94
    get isZDVcalculable(): boolean {
        return this._isZDVcalculable;
95
96
    }

97
    /**
98
99
100
     * paramètres castés au bon type
     */
    get prms(): StructureParams {
101
        return this._prms as StructureParams;
102
103
    }

Dorchies David's avatar
Dorchies David committed
104
105
106
107
108
109
110
111
    get W(): number {
        if (this.prms.W.visible) {
            return this.prms.W.v;
        } else {
            return Infinity;
        }
    }

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    /**
     * Returns the nth visible parameter (used in nghyd/PabTable)
     */
    public getNthVisibleParam(n: number): ParamDefinition {
        let i = 0;
        for (const p of this.parameterIterator) {
            if (p.visible) {
                if (n === i) {
                    return p;
                }
                i++;
            }
        }
        return undefined;
    }

Mathias Chouet's avatar
Mathias Chouet committed
128
129
130
131
    /**
     * Forwards to parent, that has vsibility over
     * all the parameters, including the Structure ones
     */
132
    public unsetCalculatedParam(except: ParamDefinition) {
Mathias Chouet's avatar
Mathias Chouet committed
133
        if (this.parent) {
134
            this.parent.unsetCalculatedParam(except);
Mathias Chouet's avatar
Mathias Chouet committed
135
136
137
        }
    }

138
139
140
141
142
143
144
145
    /**
     * Forwards to parent, that has vsibility over
     * all the parameters, including the Structure ones
     */
    public get calculatedParam(): ParamDefinition {
        if (this.parent) {
            return this.parent.calculatedParam;
        }
Dorchies David's avatar
Dorchies David committed
146
147
        // For testing purpose without ParallelStructure
        return this._calculatedParam;
148
149
    }

Mathias Chouet's avatar
Mathias Chouet committed
150
151
152
153
154
155
156
    /**
     * Forwards to parent, that has vsibility over
     * all the parameters, including the Structure ones
     */
    public set calculatedParam(p: ParamDefinition) {
        if (this.parent) {
            this.parent.calculatedParam = p;
Dorchies David's avatar
Dorchies David committed
157
158
159
        } else {
            // For testing purpose without ParallelStructure
            this._calculatedParam = p;
Mathias Chouet's avatar
Mathias Chouet committed
160
161
162
        }
    }

163
164
165
166
    /**
     * Forwards to parent, that has vsibility over
     * all the parameters, including the Structure ones
     */
167
    public findFirstCalculableParameter(otherThan?: ParamDefinition) {
168
        if (this.parent) {
169
            return this.parent.findFirstCalculableParameter(otherThan);
170
171
172
173
        }
        return undefined;
    }

Mathias Chouet's avatar
Mathias Chouet committed
174
175
176
177
178
179
180
181
182
183
    /**
     * Forwards to parent, that has visibility over
     * all the parameters, including the Structure ones
     */
    public resetDefaultCalculatedParam(requirer?: ParamDefinition) {
        if (this.parent) {
            this.parent.resetDefaultCalculatedParam(requirer);
        }
    }

184
185
186
187
188
    /**
     * Calcul de l'aire d'écoulement sur le seuil ou dans l'orifice
     */
    public abstract calcA(): number;

189
    /**
190
     * Calcul d'une équation quelle que soit l'inconnue à calculer.
191
192
193
194
     * 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
     */
195
    public Calc(sVarCalc: string, rInit?: number): Result {
196
197
        // Gestion de l'exception de calcul de W sur les seuils
        if (rInit === undefined) {
198
            rInit = this.getParameter(sVarCalc).v;
199
200
201
202
        }
        if (sVarCalc === "W" && rInit === Infinity) {
            throw new Error("Structure:Calc : Calcul de W impossible sur un seuil");
        }
Dorchies David's avatar
Dorchies David committed
203
204
205
206
207
208
        // Gestion de l'erreur de calcul de ZDV quand il n'est pas calculable
        if (sVarCalc === "ZDV" && !this.isZDVcalculable) {
            return new Result(
                new Message(MessageCode.ERROR_STRUCTURE_ZDV_PAS_CALCULABLE)
            );
        }
209

Dorchies David's avatar
Dorchies David committed
210
211
        this.prms.update_h1h2();

212
        // Gestion du débit nul
213
214
215
216
217
        const flagsNull = {
            ENUM_StructureFlowMode: StructureFlowMode.NULL,
            ENUM_StructureFlowRegime: StructureFlowRegime.NULL,
            ENUM_StructureJetType: StructureJetType.SO
        };
218
        if (sVarCalc === "Q") {
Dorchies David's avatar
Dorchies David committed
219
            if (this.prms.h1.v <= 0 || Math.abs(this.prms.h1.v - this.prms.h2.v) < 1E-20 || this.W <= 1E-20) {
220
                return new Result(0, this, flagsNull);
221
            }
222
        } else if (this.prms.Q.v === 0) {
223
            // Débit nul <=> tirant d'eau amont = tirant d'eau aval ou tout autre paramètre nul
224
            switch (sVarCalc) {
225
                case "Z1":
226
                    return new Result(this.prms.Z2.v, this, flagsNull);
227
                case "Z2":
228
                    return new Result(this.prms.Z1.v, this, flagsNull);
229
230
                default:
                    // Est-ce toujours vrai ? Nécessitera peut-être d'étendre la méthode
231
                    return new Result(0, this, flagsNull);
232
            }
Dorchies David's avatar
Dorchies David committed
233
        } else if (this.W === 0 && sVarCalc === "Z1") {
234
            return new Result(Infinity, this, flagsNull); // Si la vanne est fermée la cote amont est infinie
235
236
        }

237
238
239
        // Gestion du cas d'écoulement impossible Z1 > Z2 et Q <= 0
        if (!(sVarCalc === "Q" || sVarCalc === "Z1" || sVarCalc === "Z2")) {
            if (
240
241
                (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)
242
243
244
245
246
            ) {
                // On ferme l'ouvrage et on renvoie un code d'erreur
                let rPrm: number;
                switch (sVarCalc) {
                    case "ZDV":
Dorchies David's avatar
Dorchies David committed
247
                        rPrm = Math.max(this.prms.Z1.v, this.prms.Z2.v);
248
                        break;
249
                    default:
250
                        rPrm = 0;
251
                }
252
253
254
255
256
257
                let res: Result;
                if (this.prms.Z1.v === this.prms.Z2.v && this.prms.Q.v !== 0) {
                    res = new Result(new Message(MessageCode.ERROR_STRUCTURE_Z_EGAUX_Q_NON_NUL), this);
                } else {
                    res = new Result(new Message(MessageCode.ERROR_STRUCTURE_Q_TROP_ELEVE), this, flagsNull);
                }
Dorchies David's avatar
Dorchies David committed
258
259
                res.vCalc = rPrm;

260
                // "Les cotes et le débit ne sont pas cohérents => fermeture de l'ouvrage
Dorchies David's avatar
Dorchies David committed
261
                return res;
262
263
264
            }
        }

265
        // Gestion de l'inversion de débit : on inverse l'amont et l'aval pour le calcul
266
267
        if (sVarCalc !== "Q" && this.prms.Q.v < 0) {
            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
268
            const res: Result = super.Calc(sVarCalc, rInit);
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
            return res;
        }

        // Calcul normal hors débit nul
        return super.Calc(sVarCalc, rInit);
    }

    /**
     * Equation preprocessing
     * @return true if inverted discharge
     */
    public Equation(sVarCalc: string): Result {
        Structure.CheckEquation(sVarCalc);
        let res: Result;
284
285
286
287
288
289
290
291
        let bInverted: boolean = false;
        if (this.prms.Z1.v < this.prms.Z2.v) {
            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
            bInverted = true;
        }
        this.prms.update_h1h2();
        res = this.CalcQ();
        if (bInverted) {
292
293
294
            if (sVarCalc === "Q") {
                res.vCalc = -res.vCalc;
            }
295
            [this.prms.Z1.v, this.prms.Z2.v] = [this.prms.Z2.v, this.prms.Z1.v]; // Swap ES6 fashion
296
        }
297
        return res;
298
    }
299

300
301
302
303
304
    /**
     * Function to implement for the stage discharge equation of hydraulic structure
     */
    protected abstract CalcQ(): Result;

305
    protected getResultData() {
306
        return {
307
308
            ENUM_StructureFlowMode: this.getFlowMode(),
            ENUM_StructureFlowRegime: this.getFlowRegime(),
Dorchies David's avatar
Dorchies David committed
309
            ENUM_StructureJetType: this.getJetType()
310
        };
311
    }
312
313
314

    /**
     * paramétrage de la calculabilité des paramètres
315
     */
316
317
    protected setParametersCalculability() {
        this.prms.Q.calculability = ParamCalculability.EQUATION;
318
        this.prms.ZDV.calculability = ParamCalculability.DICHO;
319
320
321
322
        this.prms.Z1.calculability = ParamCalculability.DICHO;
        this.prms.Z2.calculability = ParamCalculability.DICHO;
        this.prms.h1.calculability = ParamCalculability.DICHO;
        this.prms.h2.calculability = ParamCalculability.DICHO;
323
        this.prms.W.calculability = ParamCalculability.FIXED;
324
325
    }

326
327
    /**
     * Give the flow mode : weir or orifice flow
328
     */
329
    protected getFlowMode(): StructureFlowMode {
Dorchies David's avatar
Dorchies David committed
330
331
        if (this.prms.h1.v > this.W) {
            this.debug("Structure.getFlowMode(h1=" + this.prms.h1.v + ",W=" + this.W + ")=ORIFICE");
332
333
            return StructureFlowMode.ORIFICE;
        } else {
Dorchies David's avatar
Dorchies David committed
334
            this.debug("Structure.getFlowMode(h1=" + this.prms.h1.v + ",W=" + this.W + ")=WEIR");
335
336
337
338
339
340
341
342
            return StructureFlowMode.WEIR;
        }

    }

    /**
     * Give the flow regime for a rectangular section : free, partially submerged or submerged flow
     */
343
    protected getFlowRegime(): StructureFlowRegime {
344
345
346
347
348
349
350
        // 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
            this.debug(
                "Structure.getFlowRegime(h1="
                + this.prms.h1.v + ",h2=" + this.prms.h2.v
Dorchies David's avatar
Dorchies David committed
351
                + ",W=" + this.W + ")=FREE");
352
            return StructureFlowRegime.FREE;
Dorchies David's avatar
Dorchies David committed
353
        } else if (this.prms.h1.v > this.W && this.prms.h2.v < (2 * this.prms.h1.v + this.W) / 3) {
354
355
356
357
            // Partially submerged only for orifices
            this.debug(
                "Structure.getFlowRegime(h1="
                + this.prms.h1.v + ",h2=" + this.prms.h2.v
Dorchies David's avatar
Dorchies David committed
358
                + ",W=" + this.W + ")=PARTIAL");
359
360
361
362
363
            return StructureFlowRegime.PARTIAL;
        } else {
            // (Totally) submerged for both weirs and orifices
            this.debug(
                "Structure.getFlowRegime(h1=" + this.prms.h1.v
Dorchies David's avatar
Dorchies David committed
364
                + ",h2=" + this.prms.h2.v + ",W=" + this.W + ")=SUBMERGED");
365
366
            return StructureFlowRegime.SUBMERGED;
        }
367
    }
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385

    /**
     * Give the Jet Type for weir flow
     * Cf. Baudoin J.M., Burgun V., Chanseau M., Larinier M., Ovidio M., SremskiW., Steinbach P. et Voegtle B., 2014.
     * Evaluer le franchissement des obstacles par les poissons. Principes et méthodes. Onema. 200 pages
     */
    protected getJetType(): StructureJetType {
        if (this.getFlowMode() === StructureFlowMode.WEIR) {
            if (Math.abs(this.prms.h1.v - this.prms.h2.v) < 0.5 * this.prms.h1.v) {
                return StructureJetType.SURFACE;
            } else {
                return StructureJetType.PLONGEANT;
            }
        } else {
            return StructureJetType.SO;
        }
    }

386
}