remous.ts 31.34 KiB
import { round, XOR } from "./base";
import { Dichotomie } from "./dichotomie";
import { Nub } from "./nub";
import { ParamCalculability, ParamDefinition, ParamDomainValue, ParamsEquation, CalculatorType } from "./param";
import { acSection, ParamsSection } from "./section/section_type";
import { cLog } from "./util/log";
import { Message, MessageCode } from "./util/message";
import { Result } from "./util/result";
import { ResultElement } from "./util/resultelement";
export enum MethodeResolution {
    Trapezes, EulerExplicite, RungeKutta4
/**
 * paramètres pour les courbes de remous
export class CourbeRemousParams extends ParamsEquation {
    /**
     * section associée
    private _section: acSection;
    /**
     * Débit amont
    // private _Qamont: ParamDefinition;
    /**
     * Tirant imposé à l'amont
    private _Yamont: ParamDefinition;
    /**
     * Tirant imposé à l'aval
    private _Yaval: ParamDefinition;
    /**
     * Longueur du bief
    private _Long: ParamDefinition;
    /**
     * Pas de discrétisation de l'espace (positif en partant de l'aval, négatif en partant de l'amont)
    private _Dx: ParamDefinition;
    /**
     * Méthode de résolution de l'équation différentielle
    private _methodeResolution: MethodeResolution;
    // constructor(rQamont: number, rYamont: number, rYAval: number, meth: MethodeResolution) {
    constructor(s: acSection, rYamont: number, rYAval: number, rLong: number, rDx: number, meth: MethodeResolution) {
        super();
        this._section = s;
        this._Yamont = new ParamDefinition(CalculatorType.CourbeRemous, "Yamont", ParamDomainValue.POS, rYamont);
        this._Yaval = new ParamDefinition(CalculatorType.CourbeRemous, "Yaval", ParamDomainValue.POS, rYAval);
        this._Long = new ParamDefinition(CalculatorType.CourbeRemous, "Long", ParamDomainValue.POS, rLong);
        this._Dx = new ParamDefinition(CalculatorType.CourbeRemous, "Dx", ParamDomainValue.POS, rDx);
        this._methodeResolution = meth;
        this.addParamDefinition(this._Yamont);
        this.addParamDefinition(this._Yaval);
        this.addParamDefinition(this._Long);
        this.addParamDefinition(this._Dx);
        this.addParamDefinitions(this._section.prms);
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
get Sn() { return this._section; } get Yamont() { return this._Yamont; } get Yaval() { return this._Yaval; } get Long() { return this._Long; } get Dx(): ParamDefinition { return this._Dx; } get methodeResolution() { return this._methodeResolution; } } /** * Calcul d'une courbe de remous */ // tslint:disable-next-line:max-classes-per-file export class CourbeRemous extends Nub { [key: string]: any; // pour pouvoir faire this['methode](); private _debugDicho: boolean = false; /** * Journal de calcul */ // private _log: cLog; private prmSect: ParamsSection; /** * Pas de discrétisation de l'espace (positif en partant de l'aval, négatif en partant de l'amont) */ private Dx: number; constructor(crp: CourbeRemousParams, dbg: boolean = false) { super(crp, dbg); // this._log = crp.Sn.log; this.prmSect = crp.Sn.prms; this.Sn.Calc("Yc"); } /** * calcul de la ligne fluviale depuis l'aval (si possible) */ public calculFluvial(): ResultElement { if (!this.Sn.HautCritique.ok) { return new ResultElement(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } let res: ResultElement; // Calcul depuis l'aval if (this.Sn.HautCritique.vCalc <= this.prms.Yaval.v) { // this._log.add(new Message(MessageCode.ERROR_REMOUS_CALCUL_FLUVIAL)); this.debug( `Condition limite aval (${this.prms.Yaval.v}) >= ` + `Hauteur critique (${this.Sn.HautCritique}) : calcul de la partie fluviale à partir de l'aval`);
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
this.Dx = this.prms.Dx.v; res = this.calcul(this.prms.Yaval.v); res.insertMessage(new Message(MessageCode.INFO_REMOUS_CALCUL_FLUVIAL)); } else { this.debug( "Condition limite aval (" + this.prms.Yaval.v + ") < Hauteur critique (" + this.Sn.HautCritique + ") : pas de calcul possible depuis l'aval"); // this._log.add(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL_DEPUIS_AVAL)); res = new ResultElement(); res.addMessage(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL_DEPUIS_AVAL)); } return res; } /** * calcul de la ligne torrentielle depuis l'amont (si possible) */ public calculTorrentiel(): ResultElement { if (!this.Sn.HautCritique.ok) { return new ResultElement(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } let res: ResultElement; // Calcul depuis l'amont if (this.Sn.HautCritique.vCalc >= this.prms.Yamont.v) { // this._log.add(new Message(MessageCode.ERROR_REMOUS_CALCUL_TORRENTIEL)); this.debug( "Condition limite amont (" + this.prms.Yamont.v + ") <= Hauteur critique (" + this.Sn.HautCritique + ") : calcul de la partie torrentielle à partir de l'amont"); this.Dx = -this.prms.Dx.v; res = this.calcul(this.prms.Yamont.v); res.insertMessage(new Message(MessageCode.INFO_REMOUS_CALCUL_TORRENTIEL)); } else { // this._log.add(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL_DEPUIS_AMONT)); this.debug( "Condition limite amont (" + this.prms.Yamont.v + ") > Hauteur critique (" + this.Sn.HautCritique + ") : pas de calcul possible depuis l'amont"); res = new ResultElement(); res.addMessage(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL_DEPUIS_AMONT)); } return res; } /** * @param val_a_cal nom de la variable à calculer */ public calculRemous(val_a_cal: string): // { // "flu": { [key: number]: number; }, // "tor": { [key: number]: number; }, // "trX": string[], // "tRes": { [key: number]: number } // } Result { const res = new Result(); // let Yc: number = this.Sn.Calc("Yc"); const rYC = this.Sn.Calc("Yc"); if (!rYC.ok) { res.addLog(rYC.log); return res; } const Yc: number = rYC.vCalc;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
const rB: Result = this.Sn.Calc("B", this.Sn.prms.YB.v); if (!rB.ok) { res.addLog(rB.log); return res; } let m: Message = new Message(MessageCode.INFO_REMOUS_LARGEUR_BERGE); // m.extraVar["B"] = this.Sn.Calc("B", this.Sn.prms.YB.v); m.extraVar.B = rB.vCalc; // this._log.add(m); res.addMessage(m); m = new Message(MessageCode.INFO_REMOUS_H_CRITIQUE); m.extraVar.Yc = Yc; // this._log.add(m); res.addMessage(m); const rYN = this.Sn.Calc("Yn"); if (!rYN.ok) { res.addLog(rYN.log); return res; } const Yn = rYN.vCalc; m = new Message(MessageCode.INFO_REMOUS_H_NORMALE); m.extraVar.Yn = Yn; // this._log.add(m); res.addMessage(m); // this.debug("largeur berge " + this.Sn.Calc("B")); // const rB2: Result = this.Sn.Calc("B") // this.debug("largeur berge " + rB2.vCalc); // this.debug("hauteur critique " + Yc); // this.Sn.HautNormale = this.Sn.Calc("Yn"); // this.debug("hauteur normale " + this.Sn.HautNormale); // this.debug("hauteur normale " + Yn); // Calcul des courbes de remous // let crbFlu: { [key: number]: number; } = this.calculFluvial(); const rCourbeFlu: ResultElement = this.calculFluvial(); // if (!rCourbeFlu.ok) { res.addLog(rCourbeFlu.log); // return res; // } // let crbTor: { [key: number]: number; } = this.calculTorrentiel(); const rCourbeTor: ResultElement = this.calculTorrentiel(); // if (!rCourbeTor.ok) { res.addLog(rCourbeTor.log); // return res; // } let crbFlu = rCourbeFlu.getExtraResult("trY"); if (crbFlu === undefined) { crbFlu = {}; } let crbTor = rCourbeTor.getExtraResult("trY"); if (crbTor === undefined) { crbTor = {}; } // this.debug("HautCritique ", this.Sn.HautCritique); this.debug("flu "); // this.logObject(crbFlu); this.debug(JSON.stringify(crbFlu)); this.debug("tor");
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
// this.logObject(crbTor); this.debug(JSON.stringify(crbTor)); // tslint:disable-next-line:forin for (const xflu in crbFlu) { const yflu = crbFlu[xflu]; // this.debug("imp x " + xflu + " flu " + this.Sn.Calc('Imp', yflu)); } // tslint:disable-next-line:forin for (const xtor in crbTor) { const ytor = crbTor[xtor]; // this.debug("imp x " + xtor + " tor " + this.Sn.Calc('Imp', ytor)); } // Détection du ressaut hydraulique const nFlu: number = this.size(crbFlu); const nTor: number = this.size(crbTor); if (nFlu !== 0 && nTor !== 0) { const firstYFlu = crbFlu[0]; const lastYTor = this.last(crbTor); // this.debug("end flu " + firstYFlu); // this.debug("end tor " + lastYTor); // this.debug("nFlu " + nFlu); // this.debug("nTor " + nTor); // this.debug("Imp flu " + this.Sn.Calc('Imp', firstYFlu)); // this.debug("Imp tor " + this.Sn.Calc('Imp', lastYTor)); let crbComplete: any; let crbPartielle: any; let iSens: number; let sSens: string; if (nFlu > nTor || (nFlu === nTor && Yn < Yc)) { // La courbe fluviale va jusqu'au bout crbComplete = crbFlu; // courbe calculée sur tout le bief crbPartielle = crbTor; // courbe calculée sur une partie seulement du bief iSens = 1; // On cherche l'aval du ressaut sSens = "amont"; this.debug("complete=flu, partielle=tor"); // this.debug("complete(flu)"); // this.debug(crbComplete); // this.debug("partielle(tor)"); // this.debug(crbPartielle); } else { // La courbe torrentielle va jusqu'au bout crbComplete = crbTor; crbPartielle = crbFlu; iSens = -1; // On cherche l'amont du ressaut sSens = "aval"; this.debug("complete=tor, partielle=flu"); // this.debug("complete(tor)"); // this.debug(crbComplete); // this.debug("partielle(flu)"); // this.debug(crbPartielle); } // Parcours des sections de la ligne d'eau la plus courte const trX: string[] = Object.keys(crbPartielle); if (iSens === -1) {// tri dans l'ordre croissant { { trX.sort((a, b) => { if (+a > +b) { return 1; } if (+a < +b) { return -1; } return 0; }); } else { // tri dans l'ordre décroissant { { trX.sort((a, b) => { if (+a > +b) { return -1; } if (+a < +b) { return 1; } return 0; }); }
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
const trXr = trX.slice(0); // copie trXr.reverse(); // this.debug("trX"); // this.debug(trX); let bRessaut = false; const Dx = this.prms.Dx.v; for (let irX = 0; irX < trX.length; irX++) { const rX: number = +trX[irX]; // this.debug("irX=" + irX); // this.debug("rX=" + rX); // this.debug("partielle[" + rX + "]=" + crbPartielle[rX]); // Calcul de l'abscisse de la section dans l'autre régime const rYCO = this.Sn.Calc("Yco", crbPartielle[rX]); // Y conjugué if (!rYCO.ok) { res.addLog(rYCO.log); return res; } const Yco = rYCO.vCalc; // this.debug("rX=" + rX + " Yco(Ypartiel=" + crbPartielle[rX] + ")=" + Yco); const rLongRst = 5 * Math.abs(crbPartielle[rX] - Yco); // Longueur du ressaut // this.debug("longueur ressaut=" + rLongRst); let xRst = rX + Math.round(iSens * rLongRst / Dx) * Dx; // Abscisse où comparer Yconj et Y // this.debug("xRst=" + xRst); // let rxRst = rX + iSens * rLongRst; // Abscisse réelle du ressaut // this.debug("xRst reel=" + (rX + iSens * rLongRst)); xRst = round(xRst, this.prmSect.iPrec.v); // this.debug("xRst (arr)=" + xRst); const impYpartielle = this.Sn.Calc("Imp", crbPartielle[rX]); // this.debug("imp(Ypartiel[rX=" + rX + "]=" + crbPartielle[rX] + ")=" + impYpartielle); if (!impYpartielle.ok) { res.addLog(impYpartielle.log); return res; } if (crbComplete[xRst] !== undefined) { // Hauteur décalée de la longueur du ressaut (il faut gérer la pente du fond) const Ydec: number = crbComplete[xRst] + rLongRst * this.prmSect.If.v * iSens; // this.debug("Ydec=" + Ydec); const impYcomplete = this.Sn.Calc("Imp", crbComplete[xRst]); // this.debug("imp(Ycomplet[xRst=" + xRst + "]=" + crbComplete[xRst] + ")=" + impYcomplete); if (!impYcomplete.ok) { res.addLog(impYcomplete.log); return res; } if (impYpartielle.vCalc > impYcomplete.vCalc) { this.debug( "Ressaut hydraulique détecté entre les abscisses " + Math.min(rX, xRst) + " et " + Math.max(rX, xRst)); m = new Message(MessageCode.INFO_REMOUS_RESSAUT_HYDRO); m.extraVar.xmin = Math.min(rX, xRst); m.extraVar.xmax = Math.max(rX, xRst); // this._log.add(m); res.addMessage(m); // this.debug("rX=" + rX + " xRst=" + xRst); // Modification de la ligne d'eau complète for (const pi of trXr) { const rXCC: number = +pi; // this.debug("rXCC=" + rXCC); if (iSens * (rXCC - rX) <= 0) {
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
delete crbComplete[rXCC]; this.debug( "Modification de la ligne d'eau complète : suppression de la valeur à rXCC=" + rXCC + ", rX=" + rX + ", iSens*(rXCC-rX)=" + (iSens * (rXCC - rX)) ); } } // Modification de la ligne d'eau partielle for (const xcn of trX) { const rXCN = +xcn; // this.debug("rXCN=" + rXCN); if (iSens * (rXCN - xRst) >= 0) { this.debug( "Modification de la ligne d'eau partielle : suppression de la valeur à rX=" + rXCN ); delete crbPartielle[rXCN]; } } bRessaut = true; break; } } } if (!bRessaut) { // Le ressaut est en dehors du canal m = new Message(MessageCode.INFO_REMOUS_RESSAUT_DEHORS); m.extraVar.sens = sSens; m.extraVar.x = +this.last(trX); // this._log.add(m); res.addMessage(m); this.debug("Ressaut hydraulique détecté à l'" + sSens + " de l'abscisse " + this.last(trX)); if (iSens === 1) { crbTor = {}; } else { crbFlu = {}; } crbPartielle = {}; // pour le log uniquement, à virer } this.debug("complete (" + (iSens === 1 ? "flu" : "tor") + ") modifiée"); // this.logObject(crbComplete); this.debug(JSON.stringify(crbComplete)); this.debug("partielle (" + (iSens === 1 ? "tor" : "flu") + ") modifiée"); // this.logObject(crbPartielle); this.debug(JSON.stringify(crbPartielle)); } // Définition des abscisses let trX: number[] = []; if (nFlu !== 0) { trX = Object.keys(crbFlu).map((k) => +k); } if (nTor !== 0) { const kTor = Object.keys(crbTor).map(k => +k); trX = trX.concat(kTor); } // this.debug("trX=" + trX); trX.sort((a, b) => { if (a > b) { return 1; } if (a < b) { return -1; } return 0; }); // this.debug("trX tri=" + trX); trX = trX.filter((elem, index, array) => { if (index > 0) { return elem !== array[index - 1];
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
} return true; }); // this.debug("trX unique=" + trX); this.debug("abscisses "); this.logArray(trX); // Calcul de la variable à calculer const tRes: { [key: number]: number } = {}; if (val_a_cal !== undefined && (nFlu !== 0 || nTor !== 0)) { for (const rX of trX) { let rY: number; const hasFlu: boolean = crbFlu[rX] !== undefined; const hasTor: boolean = crbTor[rX] !== undefined; if (hasFlu && !hasTor) { rY = crbFlu[rX]; } if (hasTor) { if (!hasFlu || (hasFlu && crbFlu[rX] === crbTor[rX])) { rY = crbTor[rX]; } } if (rY !== undefined) { // tRes[+rX] = this.Sn.Calc(val_a_cal, rY); const rVar = this.Sn.Calc(val_a_cal, rY); if (!rVar.ok) { res.addLog(rVar.log); return res; } tRes[rX] = rVar.vCalc; this.debug("X=" + rX + " Calc(" + val_a_cal + ", Y=" + rY + ")=" + tRes[rX]); } } this.debug("extra param " + val_a_cal); this.logObject(tRes); } // return { "flu": crbFlu, "tor": crbTor, "trX": trX, "tRes": tRes }; const rFlu = new ResultElement(); rFlu.addExtraResult("flu", crbFlu); res.addResult(rFlu); const rTor = new ResultElement(); rTor.addExtraResult("tor", crbTor); res.addResult(rTor); const rX = new ResultElement(); rX.addExtraResult("trX", trX); res.addResult(rX); const rVar = new ResultElement(); rVar.addExtraResult("tRes", tRes); res.addResult(rVar); return res; } public Calc(sVarCalc: string, rInit?: number, rPrec: number = 0.001): Result { if (sVarCalc === "Hs") { return this.Equation(sVarCalc); } throw new Error("CourbeRemous.Calc() : parameter " + sVarCalc + " not allowed"); }
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
public Equation(sVarCalc: string): Result { if (sVarCalc === "Hs") { // Equation de l'intégration par la méthode des trapèzes this.Sn.Reset(); // pour forcer le calcul avec la nouvelle valeur de prmSect.Y // let res: number = this.Sn.Calc('Hs') - this.Sn.Calc('J') / 2 * this.Dx; const rHS = this.Sn.Calc("Hs"); if (!rHS.ok) { return rHS; } const rJ = this.Sn.Calc("J"); if (!rJ.ok) { return rJ; } const res: number = rHS.vCalc - rJ.vCalc / 2 * this.Dx; return new Result(res); } throw new Error("CourbeRemous.Equation() : parameter " + sVarCalc + " not allowed"); } private get Sn(): acSection { return this.prms.Sn; } private get prms(): CourbeRemousParams { return this._prms as CourbeRemousParams; } protected setParametersCalculability() { this.prms.map.Y.calculability = ParamCalculability.DICHO; this.prms.Long.calculability = ParamCalculability.FREE; this.prms.map.Dx.calculability = ParamCalculability.FREE; this.prms.map.Yamont.calculability = ParamCalculability.FREE; this.prms.map.Yaval.calculability = ParamCalculability.FREE; } /** * Calcul de dy/dx (utilisé par Euler explicite et Runge-Kutta 4) * @param Y Tirant d'eau initial */ private Calc_dYdX(Y: number): Result { // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau // return - (this.prmSect.If.v - this.Sn.Calc('J', Y)) / (1 - Math.pow(this.Sn.Calc('Fr', Y), 2)); const rJ = this.Sn.Calc("J", Y); if (!rJ.ok) { return rJ; } const rFR = this.Sn.Calc("Fr", Y); if (!rFR.ok) { return rFR; } const v = - (this.prmSect.If.v - rJ.vCalc) / (1 - Math.pow(rFR.vCalc, 2)); return new Result(v); } /** * Calcul du point suivant de la courbe de remous par la méthode Euler explicite. * @param Y Tirant d'eau initial * @return Tirant d'eau */ private Calc_Y_EulerExplicite(Y: number): Result { if (!this.Sn.HautCritique.ok) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE));
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
} // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau const rDXDY = this.Calc_dYdX(Y); if (!rDXDY.ok) { return rDXDY; } // let Y2 = Y + this.Dx * this.Calc_dYdX(Y); const Y2 = Y + this.Dx * rDXDY.vCalc; if (XOR(this.Dx > 0, !(Y2 < this.Sn.HautCritique.vCalc))) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } return new Result(Y2); } /** * Calcul du point suivant de la courbe de remous par la méthode RK4. * @param Y Tirant d'eau initial * @return Tirant d'eau */ private Calc_Y_RK4(Y: number): Result { if (!this.Sn.HautCritique.ok) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } // L'appel à Calc('J') avec Y en paramètre réinitialise toutes les données dépendantes de la ligne d'eau const rDx = this.Dx; // let k1 = this.Calc_dYdX(Y); const rDXDY: Result = this.Calc_dYdX(Y); if (!rDXDY.ok) { return rDXDY; } const k1 = rDXDY.vCalc; const hc = this.Sn.HautCritique.vCalc; if (XOR(rDx > 0, !(Y + rDx / 2 * k1 < hc))) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } // let k2 = this.Calc_dYdX(Y + Dx / 2 * k1); const rDXDY2: Result = this.Calc_dYdX(Y + rDx / 2 * k1); if (!rDXDY2.ok) { return rDXDY2; } const k2 = rDXDY2.vCalc; if (XOR(rDx > 0, !(Y + rDx / 2 * k2 < hc))) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } // let k3 = this.Calc_dYdX(Y + Dx / 2 * k2); const rDXDY3: Result = this.Calc_dYdX(Y + rDx / 2 * k2); if (!rDXDY3.ok) { return rDXDY3; } const k3 = rDXDY3.vCalc; if (XOR(rDx > 0, !(Y + rDx / 2 * k3 < hc))) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } // let k4 = this.Calc_dYdX(Y + Dx * k3); const rDXDY4: Result = this.Calc_dYdX(Y + rDx * k3); if (!rDXDY4.ok) {
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
return rDXDY4; } const k4 = rDXDY4.vCalc; const Yout = Y + rDx / 6 * (k1 + 2 * (k2 + k3) + k4); // if ($this ->rDx > 0 xor !($Yout < $this ->oSect ->rHautCritique)) { return false; } if (XOR(rDx > 0, !(Yout < hc))) { const res = new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } return new Result(Yout); } /** * Calcul du point suivant de la courbe de remous par la méthode de l'intégration par trapèze * @param Y Tirant d'eau initial * @return Tirant d'eau */ private Calc_Y_Trapez(Y: number): Result { if (!this.Sn.HautCritique.ok) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } const dicho = new Dichotomie(this, "Y", this._debugDicho, "Hs"); // Calcul de H + J * \Delta x / 2 // let Trapez_Fn = this.Sn.Calc('Hs', Y) + this.Sn.Calc('J', Y) / 2 * this.Dx const rHS: Result = this.Sn.Calc("Hs", Y); if (!rHS.ok) { return rHS; } const rJ: Result = this.Sn.Calc("J", Y); if (!rJ.ok) { return rJ; } let trapezFn = rHS.vCalc + rJ.vCalc / 2 * this.Dx; // H est la charge totale. On se place dans le référentiel ou Zf de la section à calculer = 0 trapezFn -= this.Dx * this.prmSect.If.v; const r: Result = dicho.Dichotomie(trapezFn, this.prmSect.Prec.v, Y); if (!r.ok) { return r; } if (XOR(this.Dx > 0, !(r.vCalc < this.Sn.HautCritique.vCalc))) { return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE)); } // return new Result(Y2); return r; } /** * Calcul du point suivant d'une courbe de remous * @param Y Tirant d'eau initial * @return Tirant d'eau */ private Calc_Y(Y: number): Result { // let funcCalcY = 'Calc_Y_' + Resolution; // return this[funcCalcY](Y); switch (this.prms.methodeResolution) { case MethodeResolution.Trapezes: return this.Calc_Y_Trapez(Y); case MethodeResolution.RungeKutta4: return this.Calc_Y_RK4(Y);
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
case MethodeResolution.EulerExplicite: return this.Calc_Y_EulerExplicite(Y); // default: // throw new Error("CourbeRemous.Calc_Y() : type de méthode de résolution " + // MethodeResolution[this.prms.methodeResolution] + " non pris en charge"; } } private size(o: {}): number { let res: number = 0; for (const i in o) { res++; } return res; } private last(o: any): any { let res: any; for (const i in o) { res = o[i]; } return res; } /** * Calcul d'une courbe de remous en fluvial ou torrentiel * @param YCL Condition limite amont (torrentiel) ou aval (fluvial) */ private calcul(YCL: number): ResultElement { const trY: { [key: number]: number; } = {}; const res = new ResultElement(); let deb: number; let fin: number; if (this.Dx > 0) { // Calcul depuis l'aval deb = this.prms.Long.v; fin = 0; } else { // Calcul depuis l'amont deb = 0; fin = this.prms.Long.v; } const dx = -this.Dx; let lastY = YCL; trY[round(deb, this.prmSect.iPrec.v)] = lastY; // Boucle de calcul de la courbe de remous for (let x = deb + dx; (dx > 0 && x <= fin) || (dx < 0 && x >= fin); x += dx) { // this.debug("lastY " + lastY); const rY: Result = this.Calc_Y(lastY); // this.debug("calcul : x " + x + " y " + rY.vCalc); // this.debug("trY "); // this.logObject(trY); // this.debug("end trY " + this.last(trY)); // this.debug("Yn " + this.Sn.HautNormale); if (rY.ok) { // on vérifie qu'on ne traverse pas la hauteur normale (à la précision de calcul près) const prec: number = this.prms.map.Prec.v; const b1: boolean = lastY - this.Sn.HautNormale > prec; const b2: boolean = rY.vCalc - this.Sn.HautNormale > prec; if (XOR(b1, b2)) { this.debug(
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
"La pente de la ligne d'eau est trop forte à l'abscisse " + x + " m (Il faudrait réduire le pas de discrétisation)" ); const m: Message = new Message(MessageCode.ERROR_REMOUS_PENTE_FORTE); m.extraVar.x = x; // this._log.add(m); res.addMessage(m); } trY[round(x, this.prmSect.iPrec.v)] = rY.vCalc; } else { const m = new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE); m.extraVar.x = x; // this._log.add(m); res.addMessage(m); this.debug("Arrêt du calcul : Hauteur critique atteinte à l'abscisse " + x + " m"); break; } lastY = rY.vCalc; } // return trY; res.addExtraResult("trY", trY); return res; } private logArray(a: any[]) { let s = "["; let first = true; for (const e of a) { if (!first) { s += ","; } s += String(e); first = false; } s += "]"; this.debug(s); } private logObject(o: { [key: number]: number }) { if (o === undefined) { this.debug("<undefined>"); } else { const ks: string[] = Object.keys(o); ks.sort((a, b) => { if (+a > +b) { return 1; } if (+a < +b) { return -1; } return 0; }); for (const k of ks) { this.debug("[" + (+k).toFixed(3) + "]=" + o[+k]); } } } }