jalhyd
Version:
JaLHyd, a Javascript Library for Hydraulics
122 lines • 4.89 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.acNewton = void 0;
const internal_modules_1 = require("../../internal_modules");
const internal_modules_2 = require("../../internal_modules");
const internal_modules_3 = require("../../internal_modules");
const internal_modules_4 = require("../../internal_modules");
const internal_modules_5 = require("../../internal_modules");
// tslint:disable-next-line:class-name
class acNewton extends internal_modules_1.Debug {
/**
* Constructeur de la classe
* @param prms Paramètres supplémentaires (Débit, précision...)
*/
constructor(prms, maxIter, dbg = false) {
super(dbg);
this.rRelax = 1; /// Coefficient de relaxation
this.rFnPrec = 0; /// Mémorisation du Fn précédent pour détecter le changement de signe
this.iOscil = 0; /// Nombre de changement de signe de Delta
this.rTol = internal_modules_2.SessionSettings.precision;
this.Dx = internal_modules_2.SessionSettings.precision / 10;
this.iCptMax = maxIter;
}
Newton(rX) {
this.iCpt = 0;
return this.doNewton(rX);
}
/**
* Calcul de la dérivée f'(x) (peut être redéfini pour calcul analytique)
* @param rX x
* @return Calcul de la fonction
*/
CalcDer(x) {
const rFN1 = this.CalcFn(x - this.Dx);
if (!rFN1.ok) {
return rFN1;
}
const rFN2 = this.CalcFn(x + this.Dx);
if (!rFN2.ok) {
return rFN2;
}
// return (this.CalcFn(x + this.Dx) - this.CalcFn(x - this.Dx)) / (2 * this.Dx);
const v = (rFN2.vCalc - rFN1.vCalc) / (2 * this.Dx);
return new internal_modules_4.Result(v);
}
/**
* Test d'égalité à une tolérance près
* @param rFn x
* @return True si égal, False sinon
*/
FuzzyEqual(rFn) {
return (Math.abs(rFn) < this.rTol);
}
/**
* Fonction récursive de calcul de la suite du Newton
* @param rX x
* @return Solution du zéro de la fonction
*/
doNewton(rX) {
this.iCpt++;
const rFN = this.CalcFn(rX);
if (!rFN.ok) {
return rFN;
}
const rFn = rFN.vCalc;
// if (this.FuzzyEqual(rFn) || this.iCpt >= this.iCptMax)
// return new Result(rX);
if (this.FuzzyEqual(rFn)) { // convergence
return new internal_modules_4.Result(rX);
}
if (this.iCpt >= this.iCptMax) { // non convergence
const mess = new internal_modules_3.Message(internal_modules_3.MessageCode.ERROR_NEWTON_NON_CONVERGENCE);
const res = new internal_modules_5.ResultElement(mess);
res.addExtraResult("res", rX);
return new internal_modules_4.Result(res);
}
const rDER = this.CalcDer(rX);
if (!rDER.ok) {
return rDER;
}
const rDer = Math.max(-1E10, Math.min(rDER.vCalc, 1E10)); // Bornage de la dérivée pour éviter Delta=0
if (rDer !== 0) {
if ((0, internal_modules_1.XOR)(rFn < 0, this.rFnPrec < 0)) {
this.iOscil++;
if (this.rRelax > 1) {
// Sur une forte relaxation, au changement de signe on réinitialise
this.rRelax = 1;
}
else if (this.iOscil > 2) {
// On est dans le cas d'une oscillation autour de la solution
// On réduit le coefficient de relaxation
this.rRelax = this.rRelax * 0.5;
}
}
this.rFnPrec = rFn;
// tslint:disable-next-line:variable-name
const Delta = rFn / rDer;
// 2^8 = 2E8 ?
while (Math.abs(Delta * this.rRelax) < this.rTol && rFn > 10 * this.rTol && this.rRelax < 2E8) {
// On augmente le coefficicient de relaxation s'il est trop petit
this.rRelax = this.rRelax * 2;
}
let rRelax = this.rRelax;
while (rX - Delta * rRelax <= 0 && rRelax > 1E-4) {
// On diminue le coefficient de relaxation si on passe en négatif
rRelax = rRelax * 0.5; // Mais on ne le mémorise pas pour les itérations suivantes
}
rX = rX - Delta * rRelax;
// this.rDelta = Delta; ???
if (rX < 0) {
rX = this.rTol;
} // Aucune valeur recherchée ne peut être négative ou nulle
return this.doNewton(rX);
}
// Echec de la résolution
// return undefined;
const m = new internal_modules_3.Message(internal_modules_3.MessageCode.ERROR_NEWTON_DERIVEE_NULLE);
return new internal_modules_4.Result(m);
}
}
exports.acNewton = acNewton;
//# sourceMappingURL=newton.js.map