dichotomie.ts 5.13 KiB
import { Debug, Nub, Result } from "base";
export class Dichotomie extends Debug {
    /**  Pas de parcours de l'intervalle pour initialisation dichotomie */
    readonly IDEFINT = 100; 
    /** Nombre d'itérations maximum de la dichotomie */
    readonly IDICMAX = 100;  
    /**
    * Construction de la classe.
    * @param nub Noeud de calcul contenant la méthode de calcul Equation
    * @param sVarCalc Nom de la variable à calculer
    constructor(private nub: Nub, private sVarCalc: string) {
        super(false);
    /** Valeur inconnue à rechercher */
    get vX() {
        return this.nub.v[this.sVarCalc];
    /** Valeur inconnue à rechercher */
    set vX(vCalc) {
        this.nub.v[this.sVarCalc] = vCalc;
    /**
     * Méthode simulant l'opérateur booléen xor
     * @see http://www.howtocreate.co.uk/xor.html
    XOR(a, b) {
        return (a || b) && !(a && b);
    /**
     * Calcul de l'équation analytique.
     * @note Wrapper vers this.nub.Equation pour simplifier le code.
     * On utilise la première variable du tableau des variables pourvant être calculées analytiquement
     * Il faudra s'assurer que cette première variable correspond à la méthode de calcul la plus rapide
    private Calcul() {
        /**
         * @note 
        return this.nub.Equation(this.nub.sVarsEq[0]);
    /**
    * Calcul à l'ouvrage
    * @param sVarCalc Nom de la variable à calculer
    * @param rTarget Valeur cible
    * @param rtol Précision attendue du résultat
    * @param rInit Valeur initiale de l'inconnue à rechercher
    Dichotomie(rTarget: number, rTol: number, rInit: number): Result {
        let res: Result
        let XminInit = 1E-8;
        this.vX = XminInit;
        let v1: number = this.Calcul().vCalc;
        let XmaxInit: number = Math.max(1, rInit) * 100;
        this.vX = XmaxInit;
        let v2 = this.Calcul().vCalc;
        let DX = (XmaxInit - XminInit) / this.IDEFINT;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
let nIterMax = Math.floor(Math.max(XmaxInit - rInit, rInit - XminInit) / DX + 1); let Xmin = rInit; let Xmax = rInit; let X1 = rInit; let X2 = rInit; this.debug("rInit: " + rInit); this.vX = rInit; let v = this.Calcul().vCalc; v1 = v; v2 = v; this.debug(nIterMax); //** @todo : Chercher en dehors de l'intervalle en le décalant à droite ou à gauche en fonction de la valeur */ let nIter: number; for (nIter = 1; nIter < nIterMax; nIter++) { //Ouverture de l'intervalle des deux côtés : à droite puis à gauche Xmax = Xmax + DX; if (this.XOR(Xmax > XmaxInit, DX <= 0)) Xmax = XmaxInit; this.vX = Xmax; v = this.Calcul().vCalc; if (this.XOR(v1 < v2, v <= v2)) { v2 = v; X2 = Xmax; } if (this.XOR(v1 < v2, v >= v1)) { v1 = v; X1 = Xmax; } Xmin = Xmin - DX; if (this.XOR(Xmin < XminInit, DX <= 0)) { Xmin = XminInit; } this.vX = Xmin; v = this.Calcul().vCalc; if (this.XOR(v1 < v2, v <= v2)) { v2 = v; X2 = Xmin; } if (this.XOR(v1 < v2, v >= v1)) { v1 = v; X1 = Xmin; } if (this.XOR(rTarget > v1, rTarget >= v2)) { break; } } if (nIter >= this.IDEFINT) { this.debug("in if"); // Pas d'intervalle trouvé avec au moins une solution if (v2 < rTarget && v1 < rTarget) { // Cote de l'eau trop basse pour passer le débit il faut ouvrir un autre ouvrage this.vX = XmaxInit; } else { // Cote de l'eau trop grande il faut fermer l'ouvrage this.vX = XminInit; } res = this.Calcul(); res.extraVar["flag"] = -1; // la valeur cible n'est pas dans l'intervalle de recherche return res; } else { // Dichotomie this.debug("in dicho"); let X = rInit; for (nIter = 1; nIter <= this.IDICMAX; nIter++) { this.vX = X; v = this.Calcul().vCalc; if (rTarget != 0 && Math.abs(X1 - X2) <= rTol) { break; } if (this.XOR(rTarget < v, v1 <= v2)) { // rTarget < IQ et v(X1) > v(X2) ou pareil en inversant les inégalités
141142143144145146147148149150151152153154155156157158159
X1 = this.vX; } else { // rTarget < IQ et v(X1) < v(X2) ou pareil en inversant les inégalités X2 = this.vX; } X = (X2 + X1) * 0.5; this.debug((X)); } if (nIter == this.IDICMAX) { res = this.Calcul(); res.extraVar["flag"] = -1; // la valeur cible n'est pas dans l'intervalle de recherche return res; } } res.vCalc = v return ; } }