An error occurred while loading the file. Please try again.
-
Grand Francois authored
refs #339
1593583e
import { round, XOR } from "../internal_modules";
import { CalculatorType } from "../internal_modules";
import { Dichotomie } from "../internal_modules";
import { MirrorIterator } from "../internal_modules";
import { ParamCalculability } from "../internal_modules";
import { INumberIterator } from "../internal_modules";
import { ParamValues } from "../internal_modules";
import { SessionSettings } from "../internal_modules";
import { cLog } from "../internal_modules";
import { Message, MessageCode } from "../internal_modules";
import { Result } from "../internal_modules";
import { ResultElement } from "../internal_modules";
import { MethodeResolution } from "../internal_modules";
import { CourbeRemousParams } from "../internal_modules";
import { SectionNub } from "../internal_modules";
import { acSection } from "../internal_modules";
export interface ITrYResult {
trY: { [key: number]: number; };
log: cLog;
}
/**
* Calcul d'une courbe de remous
*/
export class CourbeRemous extends SectionNub {
private static _availableTargets: string[] = [
"Hs", "Hsc", "B", "P", "S", "R", "V", "Fr", "Ycor", "Ycon", "J", "I-J", "Imp", "Tau0"
];
private _debugDicho: boolean = false;
// tslint:disable-next-line:variable-name
private Dx: number;
constructor(s: acSection, crp: CourbeRemousParams, method: MethodeResolution = MethodeResolution.Trapezes,
dbg: boolean = false
) {
super(crp, dbg);
this.setCalculatorType(CalculatorType.CourbeRemous);
this.setSection(s);
this.methodeResolution = method;
// no calculated parameter
this._defaultCalculatedParam = undefined;
}
public get methodeResolution(): MethodeResolution {
return this.getPropValue("methodeResolution");
}
public set methodeResolution(m: MethodeResolution) {
this.setPropValue("methodeResolution", m);
}
public setSection(s: acSection) {
super.setSection(s);
this.setParametersCalculability(); // to override acSection's tuning
if (this.section !== undefined) {
// If from Section is neither visible nor linkable here
this.section.prms.If.visible = false;
this.section.prms.Y.visible = false;
}
}
/**
* This needs to be called before calculation if Z1, Z2, ZF1 or ZF2 was modified
*/
public setIfFromElevations() {
if (this.section !== undefined) {
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
this.section.prms.If.singleValue =
(this.prms.ZF1.v - this.prms.ZF2.v) / this.prms.Long.v;
this.section.prms.If.v = this.section.prms.If.singleValue;
}
}
public static get availableTargets() {
return CourbeRemous._availableTargets;
}
/**
* @param valACal nom de la variable à calculer
*/
public calculRemous(valACal: string): Result {
this.triggerChainCalculation();
this.copySingleValuesToSandboxValues();
this.prms.setYamontYavalFromElevations();
this.setIfFromElevations();
const res = new Result(undefined, this);
// vérifier qu'il y a de l'eau à l'amont / à l'aval
if (this.prms.ZF1.singleValue >= this.prms.Z1.singleValue) {
res.globalLog.add(new Message(MessageCode.WARNING_UPSTREAM_BOTTOM_HIGHER_THAN_WATER));
}
if (this.prms.ZF2.singleValue >= this.prms.Z2.singleValue) {
res.globalLog.add(new Message(MessageCode.WARNING_DOWNSTREAM_BOTTOM_HIGHER_THAN_WATER));
}
// s'il n'y en a nulle part, on arrête tout
if (
this.prms.ZF1.singleValue >= this.prms.Z1.singleValue
&& this.prms.ZF2.singleValue >= this.prms.Z2.singleValue
) {
res.globalLog.add(new Message(MessageCode.ERROR_REMOUS_NO_WATER_LINE));
return res;
}
// si le pas de discrétisation est inférieur à la longueur du bief
if (this.prms.Dx.singleValue >= this.prms.Long.singleValue) {
res.globalLog.add(new Message(MessageCode.ERROR_REMOUS_PAS_SUPERIEUR_BIEF));
return res;
}
// let Yc: number = this.Sn.CalcSection("Yc");
const rYC = this.Sn.CalcSection("Yc");
if (!rYC.ok) {
res.addLog(rYC.log);
return res;
}
// tslint:disable-next-line:variable-name
const Yc: number = rYC.vCalc;
const rB: Result = this.Sn.CalcSection("B", this.Sn.prms.YB.v);
if (!rB.ok) {
res.addLog(rB.log);
return res;
}
let m = new Message(MessageCode.INFO_REMOUS_H_CRITIQUE);
m.extraVar.Yc = Yc;
// this._log.add(m);
res.addMessage(m);
const rYN = this.Sn.CalcSection("Yn");
// tslint:disable-next-line:variable-name
let Yn: number;
if (!rYN.ok) {
const mc = rYN.log.messages[0].code;
if (mc === MessageCode.ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF) {
res.addMessage(new Message(MessageCode.WARNING_YN_SECTION_PENTE_NEG_NULLE_HNORMALE_INF));
} else if (mc === MessageCode.ERROR_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE) {
res.addMessage(new Message(MessageCode.WARNING_YN_SECTION_NON_CONVERGENCE_NEWTON_HNORMALE));
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
}
Yn = 2 * Yc; // si le calcul de Yn échoue, on est en régime fluvial, d'où un Yn imposé > Yc
} else {
// tslint:disable-next-line:variable-name
Yn = rYN.vCalc;
m = new Message(MessageCode.INFO_REMOUS_H_NORMALE, { Yn });
res.addMessage(m);
}
// this.debug("largeur berge " + this.Sn.CalcSection("B"));
// const rB2: Result = this.Sn.CalcSection("B")
// this.debug("largeur berge " + rB2.vCalc);
// this.debug("hauteur critique " + Yc);
// this.Sn.HautNormale = this.Sn.CalcSection("Yn");
// this.debug("hauteur normale " + this.Sn.HautNormale);
// this.debug("hauteur normale " + Yn);
// Calcul des courbes de remous
const xValues = new ParamValues();
xValues.setValues(0, this.prms.Long.v, this.prms.Dx.v);
// vérifier les tirants d'eau amont/aval par rapport à la hauteur critique
if (
this.Sn.HautCritique.vCalc > this.prms.Yaval.v
&& this.Sn.HautCritique.vCalc < this.prms.Yamont.v
) {
res.globalLog.add(new Message(MessageCode.ERROR_REMOUS_PAS_CALCUL));
return res;
}
// on ne peut pas calculer la courbe fluviale s'il ny 'a pas d'eau à l'aval
let rCourbeFlu: ITrYResult;
if (this.prms.ZF2.singleValue < this.prms.Z2.singleValue) {
rCourbeFlu = this.calculFluvial(xValues);
res.addLog(rCourbeFlu.log);
}
// on ne peut pas calculer la courbe torrentielle s'il ny 'a pas d'eau à l'amont
let rCourbeTor: ITrYResult;
if (this.prms.ZF1.singleValue < this.prms.Z1.singleValue) {
rCourbeTor = this.calculTorrentiel(xValues);
res.addLog(rCourbeTor.log);
}
let crbFlu;
if (rCourbeFlu?.trY !== undefined) {
crbFlu = rCourbeFlu.trY;
} else {
crbFlu = {};
}
let crbTor;
if (rCourbeTor?.trY !== undefined) {
crbTor = rCourbeTor.trY;
} else {
crbTor = {};
}
// this.debug("HautCritique ", this.Sn.HautCritique);
this.debug("flu");
// this.logObject(crbFlu);
this.debug(JSON.stringify(crbFlu));
this.debug("tor");
// this.logObject(crbTor);
this.debug(JSON.stringify(crbTor));
/* // tslint:disable-next-line:forin
for (const xflu in crbFlu) {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
const yflu = crbFlu[xflu];
// this.debug("imp x " + xflu + " flu " + this.Sn.CalcSection('Imp', yflu));
}
// tslint:disable-next-line:forin
for (const xtor in crbTor) {
const ytor = crbTor[xtor];
// this.debug("imp x " + xtor + " tor " + this.Sn.CalcSection('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.CalcSection('Imp', firstYFlu));
// this.debug("Imp tor " + this.Sn.CalcSection('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;
});
}
const trXr = trX.slice(0); // copie
trXr.reverse();
// this.debug("trX");
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
// this.debug(trX);
let bRessaut = false;
// tslint:disable-next-line:variable-name
const Dx = xValues.step;
// tslint:disable-next-line:prefer-for-of
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.CalcSection("Ycon", crbPartielle[rX]); // Y conjugué
if (!rYCO.ok) {
res.addLog(rYCO.log);
return res;
}
// tslint:disable-next-line:variable-name
const Ycon = rYCO.vCalc;
// this.debug("rX=" + rX + " Ycon(Ypartiel=" + crbPartielle[rX] + ")=" + Ycon);
const rLongRst = 5 * Math.abs(crbPartielle[rX] - Ycon); // 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.section.prms.iPrec);
// this.debug("xRst (arr)=" + xRst);
const impYpartielle = this.Sn.CalcSection("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.section.prms.If.v * iSens;
// this.debug("Ydec=" + Ydec);
const impYcomplete = this.Sn.CalcSection("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 (
(rX !== xRst && iSens * (rXCC - rX) <= 0)
|| (rX === xRst && iSens * (rXCC - rX) < 0)
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
) {
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 (
(rX !== xRst && iSens * (rXCN - xRst) >= 0)
|| (rX === xRst && 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 trXabsc: number[] = [];
if (nFlu !== 0) {
trXabsc = Object.keys(crbFlu).map((k) => +k);
}
if (nTor !== 0) {
const kTor = Object.keys(crbTor).map((k) => +k);
trXabsc = trXabsc.concat(kTor);
}
// this.debug("trX=" + trX);
trXabsc.sort((a, b) => {
if (a > b) { return 1; }
if (a < b) { return -1; }
return 0;
});
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
// this.debug("trX tri=" + trX);
trXabsc = trXabsc.filter((elem, index, array) => { // deduplicate
if (index > 0) {
return elem !== array[index - 1];
}
return true;
});
// this.debug("trX unique=" + trX);
this.debug("abscisses ");
this.logArray(trXabsc);
// est-ce que ça déborde ?
let xDebordeMin;
let xDebordeMax;
// compilation des résultats
for (const x of trXabsc) {
let ligneDeau;
if (crbFlu[x] === undefined) {
ligneDeau = crbTor[x];
} else if (crbTor[x] === undefined) {
ligneDeau = crbFlu[x];
} else {
ligneDeau = Math.max(crbFlu[x], crbTor[x]);
}
const re = new ResultElement({ ZW: ligneDeau + this.getCoteFond(x) });
re.addExtraResult("X", x);
re.addExtraResult("Y", ligneDeau);
if (crbFlu[x]) {
re.addExtraResult("flu", crbFlu[x] + this.getCoteFond(x));
}
if (crbTor[x]) {
re.addExtraResult("tor", crbTor[x] + this.getCoteFond(x));
}
// Détection du débordement
if (xDebordeMin === undefined) {
if (ligneDeau > this.section.prms.YB.v) {
xDebordeMin = x;
}
} else {
if (xDebordeMax === undefined && ligneDeau <= this.section.prms.YB.v) {
xDebordeMax = x;
}
}
// Calcul de la variable à calculer
if (valACal) {
if (ligneDeau !== undefined) {
const rVar = this.Sn.CalcSection(valACal, ligneDeau);
if (!rVar.ok) {
res.addLog(rVar.log);
} else {
let val = rVar.vCalc;
if (["Hs", "Hsc", "Ycor", "Ycon"].includes(valACal)) {
val += this.getCoteFond(x);
}
re.addExtraResult(valACal, val);
}
}
}
res.addResultElement(re);
}
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
if (xDebordeMin !== undefined || xDebordeMax !== undefined) {
xDebordeMin = (xDebordeMin === undefined) ? trXabsc[0] : xDebordeMin;
xDebordeMax = (xDebordeMax === undefined) ? trXabsc[trXabsc.length - 1] : xDebordeMax;
const md = new Message(MessageCode.WARNING_SECTION_OVERFLOW_ABSC);
md.extraVar.xa = xDebordeMin;
md.extraVar.xb = xDebordeMax;
res.globalLog.add(md);
}
return res;
}
/**
* Calcule un seul point de la courbe, uniquement pour le solveur de la méthode Trapezes
* @WARNING scorie toute pourrie
*/
public Calc(sVarCalc: string, rInit?: number): Result {
this.prms.setYamontYavalFromElevations();
this.setIfFromElevations();
if (sVarCalc === "Hs") {
return this.Equation("Hs");
}
throw new Error("CourbeRemous.Calc() : parameter " + sVarCalc + " not allowed");
}
public Equation(sVarCalc: string): Result {
if (sVarCalc === "Hs") {
const rHS: number = this.CalcHS();
return new Result(rHS, this);
}
throw new Error("CourbeRemous.Equation() : parameter " + sVarCalc + " not allowed");
}
/**
* Effectue une série de calculs sur un paramètre; déclenche le calcul en chaîne
* des modules en amont si nécessaire
* @param rInit solution approximative du paramètre
* @param sDonnee éventuel symbole / paire symbole-uid du paramètre à calculer
*/
public CalcSerie(rInit?: number): Result {
const varCalc = this.getPropValue("varCalc");
const res = this.calculRemous(varCalc);
return res;
}
public CalcHS(): number {
// Equation de l'intégration par la méthode des trapèzes
this.Sn.Reset(); // pour forcer le calcul avec la nouvelle valeur de section.prms.Y
return this.Sn.CalcSection("Hs").vCalc - this.Sn.CalcSection("J").vCalc / 2 * this.Dx;
}
public get Sn(): acSection {
return this.section;
}
get prms(): CourbeRemousParams {
return this._prms as CourbeRemousParams;
}
public isComputable(): boolean {
if (super.isComputable()) {
// au moins Z1 ou Z2 doit être défini
const z1 = this.prms.Z1;
const z2 = this.prms.Z2;
return z1.isDefined || z2.isDefined;
}
return false;
}
/**
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
* Retourne la cote de fond à l'abscisse x
* @param x abscisse en m (0 = amont)
*/
public getCoteFond(x: number) {
return (this.prms.ZF1.v - this.prms.ZF2.v) * (1 - x / this.prms.Long.v) + this.prms.ZF2.v;
}
/**
* calcul de la ligne fluviale depuis l'aval (si possible)
*/
public calculFluvial(xValues: ParamValues): ITrYResult {
let res: ITrYResult = {
log: new cLog(),
trY: {}
};
if (!this.Sn.HautCritique.ok) {
res.log.add(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE));
return res;
}
if (this.Sn.HautCritique.vCalc > this.prms.Yaval.v) {
this.debug(
"Condition limite aval (" + this.prms.Yaval.v +
") < Hauteur critique (" + this.Sn.HautCritique +
") : pas de calcul possible depuis l'aval");
res.log.add(new Message(MessageCode.WARNING_REMOUS_PAS_CALCUL_DEPUIS_AVAL));
}
// Calcul depuis l'aval
if (this.Sn.HautCritique.vCalc <= this.prms.Yaval.v) {
this.debug(
`Condition limite aval (${this.prms.Yaval.v}) >= ` +
`Hauteur critique (${this.Sn.HautCritique}) : calcul de la partie fluviale à partir de l'aval`);
this.Dx = this.prms.Dx.v;
xValues.initValuesIterator(true, undefined, true);
// reverse iterator does not work here if Dx is not a multiple of Long @see jalhyd#147
// ex: Long = 10, Dx = 3
// forward: [ 0, 3, 6, 9, 10 ]
// reverse: [ 10, 7, 4, 1, 0 ] instead of [ 10, 9, 6, 3, 0 ]
const mirror = new MirrorIterator(xValues);
res = this.calcul(this.prms.Yaval.v, mirror);
res.log.insert(new Message(MessageCode.INFO_REMOUS_CALCUL_FLUVIAL));
}
return res;
}
/**
* calcul de la ligne torrentielle depuis l'amont (si possible)
*/
public calculTorrentiel(xValues: ParamValues): ITrYResult {
let res: ITrYResult = {
log: new cLog(),
trY: {}
};
if (!this.Sn.HautCritique.ok) {
res.log.add(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE));
return res;
}
if (this.Sn.HautCritique.vCalc < this.prms.Yamont.v) {
this.debug(
"Condition limite amont (" + this.prms.Yamont.v +
") > Hauteur critique (" + this.Sn.HautCritique +
") : pas de calcul possible depuis l'amont");
res.log.add(new Message(MessageCode.WARNING_REMOUS_PAS_CALCUL_DEPUIS_AMONT));
}
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
// Calcul depuis l'amont
if (this.Sn.HautCritique.vCalc >= this.prms.Yamont.v) {
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;
xValues.initValuesIterator(false, undefined, true);
res = this.calcul(this.prms.Yamont.v, xValues);
res.log.insert(new Message(MessageCode.INFO_REMOUS_CALCUL_TORRENTIEL));
}
return res;
}
protected setParametersCalculability() {
this.prms.Long.calculability = ParamCalculability.FIXED;
this.prms.Dx.calculability = ParamCalculability.FIXED;
this.prms.Yamont.calculability = ParamCalculability.FIXED;
this.prms.Yaval.calculability = ParamCalculability.FIXED;
this.prms.Z1.calculability = ParamCalculability.FIXED;
this.prms.Z2.calculability = ParamCalculability.FIXED;
this.prms.ZF1.calculability = ParamCalculability.FIXED;
this.prms.ZF2.calculability = ParamCalculability.FIXED;
// section params
if (this.section) {
this.section.prms.Ks.calculability = ParamCalculability.FIXED;
this.section.prms.Q.calculability = ParamCalculability.FIXED;
this.section.prms.If.calculability = ParamCalculability.FIXED;
this.section.prms.YB.calculability = ParamCalculability.FIXED;
this.section.prms.Y.calculability = ParamCalculability.FIXED;
this.section.prms.LargeurBerge.calculability = ParamCalculability.FIXED;
// parameters depending on section type
const D = this.section.getParameter("D");
if (D) {
D.calculability = ParamCalculability.FIXED;
}
const k = this.section.getParameter("k");
if (k) {
k.calculability = ParamCalculability.FIXED;
}
const fruit = this.section.getParameter("Fruit");
if (fruit) {
fruit.calculability = ParamCalculability.FIXED;
}
const largeurFond = this.section.getParameter("LargeurFond");
if (largeurFond) {
largeurFond.calculability = ParamCalculability.FIXED;
}
}
}
protected adjustChildParameters(): void {
this.section.prms.Y.calculability = ParamCalculability.DICHO;
}
/**
* 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.section.prms.If.v - this.Sn.CalcSection('J', Y))
// / (1 - Math.pow(this.Sn.CalcSection('Fr', Y), 2));
const rJ = this.Sn.CalcSection("J", Y);
if (!rJ.ok) {
return rJ;
}
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
const rFR = this.Sn.CalcSection("Fr", Y);
if (!rFR.ok) {
return rFR;
}
const v = - (this.section.prms.If.v - rJ.vCalc) / (1 - Math.pow(rFR.vCalc, 2));
return new Result(v, this);
}
/**
* 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), this);
}
// 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;
return new Result(Y2, this);
}
/**
* 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), this);
}
// 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), this);
}
// let k2 = this.Calc_dYdX(Y + Dx / 2 * k1);
const rDXDY2: Result = this.Calc_dYdX(Math.max(Y + rDx / 2 * k1, 0));
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), this);
}
// let k3 = this.Calc_dYdX(Y + Dx / 2 * k2);
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
const rDXDY3: Result = this.Calc_dYdX(Math.max(Y + rDx / 2 * k2, 0));
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), this);
}
// let k4 = this.Calc_dYdX(Y + Dx * k3);
const rDXDY4: Result = this.Calc_dYdX(Math.max(Y + rDx * k3, 0));
if (!rDXDY4.ok) {
return rDXDY4;
}
const k4 = rDXDY4.vCalc;
// tslint:disable-next-line:variable-name
const Yout = Math.max(Y + rDx / 6 * (k1 + 2 * (k2 + k3) + k4), 0);
// 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), this);
return res;
}
return new Result(Yout, this);
}
/**
* 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), this);
}
const dicho = new Dichotomie(this, "Y", this._debugDicho, this.CalcHS);
// Calcul de H + J * \Delta x / 2
// let Trapez_Fn = this.Sn.CalcSection('Hs', Y) + this.Sn.CalcSection('J', Y) / 2 * this.Dx
const rHS: Result = this.Sn.CalcSection("Hs", Y);
if (!rHS.ok) {
return rHS;
}
const rJ: Result = this.Sn.CalcSection("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.section.prms.If.v;
const r: Result = dicho.Dichotomie(trapezFn, SessionSettings.precision, Y);
if (!r.ok) {
return r;
}
// return new Result(Y2, this);
return r;
}
/**
* Calcul du point suivant d'une courbe de remous
* @param Y Tirant d'eau initial
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
* @return Tirant d'eau
*/
private Calc_Y(Y: number): Result {
// let funcCalcY = 'Calc_Y_' + Resolution;
// return this[funcCalcY](Y);
let res: Result;
const methodeResolution: MethodeResolution = this.getPropValue("methodeResolution");
switch (methodeResolution) {
case MethodeResolution.Trapezes:
res = this.Calc_Y_Trapez(Y);
break;
case MethodeResolution.RungeKutta4:
res = this.Calc_Y_RK4(Y);
break;
case MethodeResolution.EulerExplicite:
res = this.Calc_Y_EulerExplicite(Y);
break;
default:
throw new Error("CourbeRemous.Calc_Y() : type de méthode de résolution " +
MethodeResolution[methodeResolution] + " non pris en charge");
}
if (!res.ok || XOR(this.Dx > 0, !(res.vCalc < this.Sn.HautCritique.vCalc))) {
return new Result(new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE), this);
}
return res;
}
private size(o: {}): number {
return Object.keys(o).length;
}
private last(o: any): any {
let res: any;
// tslint:disable-next-line:forin
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, varParam: INumberIterator): ITrYResult {
const res: ITrYResult = {
log: new cLog(),
trY: {}
};
const abs0 = varParam.next().value;
let lastY = YCL;
res.trY[round(abs0, this.section.prms.iPrec)] = lastY;
// Boucle de calcul de la courbe de remous
while (varParam.hasNext) {
const x = varParam.next().value;
// 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) {
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
// on vérifie qu'on ne traverse pas la hauteur normale (à la précision de calcul près)
const prec = SessionSettings.precision;
const b1: boolean = lastY - this.Sn.HautNormale > prec;
const b2: boolean = rY.vCalc - this.Sn.HautNormale > prec;
if (XOR(b1, b2)) {
this.debug(
"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.log.add(m);
}
// ligne d'eau
res.trY[round(x, this.section.prms.iPrec)] = rY.vCalc;
} else {
const m = new Message(MessageCode.WARNING_REMOUS_ARRET_CRITIQUE);
m.extraVar.x = x;
// this._log.add(m);
res.log.add(m);
this.debug("Arrêt du calcul : Hauteur critique atteinte à l'abscisse " + x + " m");
break;
}
lastY = rY.vCalc;
}
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]);
}
}
}
}